diff --git a/autotests/libs/autoincrementtest.cpp b/autotests/libs/autoincrementtest.cpp index 72d36d95b..6259c7123 100644 --- a/autotests/libs/autoincrementtest.cpp +++ b/autotests/libs/autoincrementtest.cpp @@ -1,130 +1,129 @@ /* Copyright (c) 2009 Thomas McGuire This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "autoincrementtest.h" #include "agentinstance.h" #include "agentmanager.h" #include "collectioncreatejob.h" #include "collectiondeletejob.h" #include "control.h" #include "item.h" #include "itemcreatejob.h" #include "itemdeletejob.h" #include -#include "test_utils.h" using namespace Akonadi; QTEST_AKONADIMAIN(AutoIncrementTest) void AutoIncrementTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AkonadiTest::setAllResourcesOffline(); - itemTargetCollection = Collection(collectionIdFromPath(QStringLiteral("res2/space folder"))); + itemTargetCollection = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(itemTargetCollection.isValid()); - collectionTargetCollection = Collection(collectionIdFromPath(QStringLiteral("res3"))); + collectionTargetCollection = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); QVERIFY(collectionTargetCollection.isValid()); } Akonadi::ItemCreateJob *AutoIncrementTest::createItemCreateJob() { QByteArray payload("Hello world"); Item item(-1); item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload(payload); return new ItemCreateJob(item, itemTargetCollection); } Akonadi::CollectionCreateJob *AutoIncrementTest::createCollectionCreateJob(int number) { Collection collection; collection.setParentCollection(collectionTargetCollection); collection.setName(QStringLiteral("testCollection") + QString::number(number)); return new CollectionCreateJob(collection); } void AutoIncrementTest::testItemAutoIncrement() { QList itemsToDelete; Item::Id lastId = -1; // Create 20 test items for (int i = 0; i < 20; i++) { ItemCreateJob *job = createItemCreateJob(); AKVERIFYEXEC(job); Item newItem = job->item(); QVERIFY(newItem.id() > lastId); lastId = newItem.id(); itemsToDelete.append(newItem); } // Delete the 20 items for (const Item &item : qAsConst(itemsToDelete)) { ItemDeleteJob *job = new ItemDeleteJob(item); AKVERIFYEXEC(job); } // Restart the server, then test item creation again. The new id of the item // should be higher than all ids before. - restartAkonadiServer(); + AkonadiTest::restartAkonadiServer(); ItemCreateJob *job = createItemCreateJob(); AKVERIFYEXEC(job); Item newItem = job->item(); QVERIFY(newItem.id() > lastId); lastId = newItem.id(); } void AutoIncrementTest::testCollectionAutoIncrement() { Collection::List collectionsToDelete; Collection::Id lastId = -1; // Create 20 test collections for (int i = 0; i < 20; i++) { CollectionCreateJob *job = createCollectionCreateJob(i); AKVERIFYEXEC(job); Collection newCollection = job->collection(); QVERIFY(newCollection.id() > lastId); lastId = newCollection.id(); collectionsToDelete.append(newCollection); } // Delete the 20 collections foreach (const Collection &collection, collectionsToDelete) { CollectionDeleteJob *job = new CollectionDeleteJob(collection); AKVERIFYEXEC(job); } // Restart the server, then test collection creation again. The new id of the collection // should be higher than all ids before. - restartAkonadiServer(); + AkonadiTest::restartAkonadiServer(); CollectionCreateJob *job = createCollectionCreateJob(0); AKVERIFYEXEC(job); Collection newCollection = job->collection(); QVERIFY(newCollection.id() > lastId); lastId = newCollection.id(); } diff --git a/autotests/libs/cachetest.cpp b/autotests/libs/cachetest.cpp index 1390e6cb5..8d3e989b3 100644 --- a/autotests/libs/cachetest.cpp +++ b/autotests/libs/cachetest.cpp @@ -1,157 +1,156 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" - #include "collection.h" #include "collectionfetchjob.h" #include "collectionmodifyjob.h" #include "item.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "agentmanager.h" #include "agentinstance.h" #include "itemcopyjob.h" +#include "qtest_akonadi.h" #include using namespace Akonadi; class CacheTest : public QObject { Q_OBJECT private: void enableAgent(const QString &id, bool enable) { auto instance = AgentManager::self()->instance(id); QVERIFY(instance.isValid()); instance.setIsOnline(enable); QTRY_COMPARE(Akonadi::AgentManager::self()->instance(id).isOnline(), enable); } private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testRetrievalErrorBurst() // caused rare server crashs with old item retrieval code { - Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); enableAgent(QStringLiteral("akonadi_knut_resource_0"), false); ItemFetchJob *fetch = new ItemFetchJob(col, this); fetch->fetchScope().fetchFullPayload(true); QVERIFY(!fetch->exec()); } void testResourceRetrievalOnFetch_data() { QTest::addColumn("item"); QTest::addColumn("resourceEnabled"); QTest::newRow("resource online") << Item(1) << true; QTest::newRow("resource offline") << Item(2) << false; } void testResourceRetrievalOnFetch() { QFETCH(Item, item); QFETCH(bool, resourceEnabled); ItemFetchJob *fetch = new ItemFetchJob(item, this); fetch->fetchScope().fetchFullPayload(); fetch->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); item = fetch->items().first(); QVERIFY(item.isValid()); QVERIFY(!item.hasPayload()); enableAgent(QStringLiteral("akonadi_knut_resource_0"), resourceEnabled); fetch = new ItemFetchJob(item, this); fetch->fetchScope().fetchFullPayload(); QCOMPARE(fetch->exec(), resourceEnabled); if (resourceEnabled) { QCOMPARE(fetch->items().count(), 1); item = fetch->items().first(); QVERIFY(item.isValid()); QVERIFY(item.hasPayload()); QVERIFY(item.revision() > 0); // was changed by the resource delivering the payload } fetch = new ItemFetchJob(item, this); fetch->fetchScope().fetchFullPayload(); fetch->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); item = fetch->items().first(); QVERIFY(item.isValid()); QCOMPARE(item.hasPayload(), resourceEnabled); } void testResourceRetrievalOnCopy_data() { QTest::addColumn("item"); QTest::addColumn("resourceEnabled"); QTest::newRow("online") << Item(3) << true; QTest::newRow("offline") << Item(4) << false; } void testResourceRetrievalOnCopy() { QFETCH(Item, item); QFETCH(bool, resourceEnabled); ItemFetchJob *fetch = new ItemFetchJob(item, this); fetch->fetchScope().fetchFullPayload(); fetch->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); item = fetch->items().first(); QVERIFY(item.isValid()); QVERIFY(!item.hasPayload()); enableAgent(QStringLiteral("akonadi_knut_resource_0"), resourceEnabled); - Collection dest(collectionIdFromPath(QStringLiteral("res3"))); + Collection dest(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); QVERIFY(dest.isValid()); ItemCopyJob *copy = new ItemCopyJob(item, dest, this); QCOMPARE(copy->exec(), resourceEnabled); fetch = new ItemFetchJob(item, this); fetch->fetchScope().fetchFullPayload(); fetch->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); item = fetch->items().first(); QVERIFY(item.isValid()); QCOMPARE(item.hasPayload(), resourceEnabled); } }; QTEST_AKONADIMAIN(CacheTest) #include "cachetest.moc" diff --git a/autotests/libs/collectioncopytest.cpp b/autotests/libs/collectioncopytest.cpp index a43c11c03..b2e9aa9ee 100644 --- a/autotests/libs/collectioncopytest.cpp +++ b/autotests/libs/collectioncopytest.cpp @@ -1,133 +1,133 @@ /* Copyright (c) 2008 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "agentinstance.h" #include "agentmanager.h" #include "control.h" #include "collectioncopyjob.h" #include "collectionfetchjob.h" #include "item.h" #include "itemfetchjob.h" #include "itemfetchscope.h" -#include "test_utils.h" +#include "qtest_akonadi.h" #include using namespace Akonadi; class CollectionCopyTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); // switch target resources offline to reduce interference from them foreach (Akonadi::AgentInstance agent, Akonadi::AgentManager::self()->instances()) { //krazy:exclude=foreach if (agent.identifier() == QLatin1String("akonadi_knut_resource_2")) { agent.setIsOnline(false); } } } void testCopy() { - const Collection target(collectionIdFromPath(QStringLiteral("res3"))); - Collection source(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection target(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); + Collection source(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(target.isValid()); QVERIFY(source.isValid()); // obtain reference listing CollectionFetchJob *fetch = new CollectionFetchJob(source, CollectionFetchJob::Base); AKVERIFYEXEC(fetch); QCOMPARE(fetch->collections().count(), 1); source = fetch->collections().first(); QVERIFY(source.isValid()); fetch = new CollectionFetchJob(source, CollectionFetchJob::Recursive); AKVERIFYEXEC(fetch); QMap referenceData; Collection::List cols = fetch->collections(); cols << source; for (const Collection &c : qAsConst(cols)) { ItemFetchJob *job = new ItemFetchJob(c, this); AKVERIFYEXEC(job); referenceData.insert(c, job->items()); } // actually copy the collection CollectionCopyJob *copy = new CollectionCopyJob(source, target); AKVERIFYEXEC(copy); // list destination and check if everything has arrived CollectionFetchJob *list = new CollectionFetchJob(target, CollectionFetchJob::Recursive); AKVERIFYEXEC(list); cols = list->collections(); QCOMPARE(cols.count(), referenceData.count()); for (QMap::ConstIterator it = referenceData.constBegin(), end = referenceData.constEnd(); it != end; ++it) { QVERIFY(!cols.contains(it.key())); Collection col; for (const Collection &c : qAsConst(cols)) { if (it.key().name() == c.name()) { col = c; } } QVERIFY(col.isValid()); QCOMPARE(col.resource(), QStringLiteral("akonadi_knut_resource_2")); QVERIFY(col.remoteId().isEmpty()); ItemFetchJob *job = new ItemFetchJob(col, this); job->fetchScope().fetchFullPayload(); job->fetchScope().setCacheOnly(true); AKVERIFYEXEC(job); QCOMPARE(job->items().count(), it.value().count()); foreach (const Item &item, job->items()) { QVERIFY(!it.value().contains(item)); QVERIFY(item.remoteId().isEmpty()); QVERIFY(item.hasPayload()); } } } void testIlleagalCopy() { // invalid source CollectionCopyJob *copy = new CollectionCopyJob(Collection(), Collection(1)); QVERIFY(!copy->exec()); // non-existing source copy = new CollectionCopyJob(Collection(INT_MAX), Collection(1)); QVERIFY(!copy->exec()); // invalid target copy = new CollectionCopyJob(Collection(1), Collection()); QVERIFY(!copy->exec()); // non-existing target copy = new CollectionCopyJob(Collection(1), Collection(INT_MAX)); QVERIFY(!copy->exec()); } }; QTEST_AKONADIMAIN(CollectionCopyTest) #include "collectioncopytest.moc" diff --git a/autotests/libs/collectioncreatetest.cpp b/autotests/libs/collectioncreatetest.cpp index 61a27c852..f6ebeb73f 100644 --- a/autotests/libs/collectioncreatetest.cpp +++ b/autotests/libs/collectioncreatetest.cpp @@ -1,67 +1,67 @@ /* * Copyright 2017 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ -#include "test_utils.h" #include "collectioncreatejob.h" #include "collectionfetchjob.h" #include "collectiondeletejob.h" #include "entitydisplayattribute.h" +#include "qtest_akonadi.h" using namespace Akonadi; class CollectionCreateTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testCreateCollection() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy spy(monitor.get(), &Monitor::collectionAdded); Collection col; col.setName(QLatin1String("test_collection")); col.setContentMimeTypes({ Collection::mimeType() }); - col.setParentCollection(Collection(collectionIdFromPath(QLatin1String("res1")))); + col.setParentCollection(Collection(AkonadiTest::collectionIdFromPath(QLatin1String("res1")))); col.setRights(Collection::AllRights); CollectionCreateJob *cj = new CollectionCreateJob(col, this); AKVERIFYEXEC(cj); col = cj->collection(); QVERIFY(col.isValid()); QTRY_COMPARE(spy.count(), 1); auto ntfCol = spy.at(0).at(0).value(); QCOMPARE(col, ntfCol); CollectionDeleteJob *dj = new CollectionDeleteJob(col, this); AKVERIFYEXEC(dj); } }; QTEST_AKONADIMAIN(CollectionCreateTest) #include "collectioncreatetest.moc" diff --git a/autotests/libs/collectioncreator.cpp b/autotests/libs/collectioncreator.cpp index 6e34ce2cb..7a3c6bfe6 100644 --- a/autotests/libs/collectioncreator.cpp +++ b/autotests/libs/collectioncreator.cpp @@ -1,89 +1,88 @@ /* Copyright (c) 2006, 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "agentinstance.h" #include "agentmanager.h" #include "collectioncreatejob.h" #include "collectionpathresolver.h" #include "transactionjobs.h" #include "qtest_akonadi.h" -#include "test_utils.h" using namespace Akonadi; class CollectionCreator : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); AkonadiTest::setAllResourcesOffline(); } void createCollections_data() { QTest::addColumn("count"); QTest::addColumn("useTransaction"); QList counts = QList() << 1 << 10 << 100 << 1000; QList transactions = QList() << false << true; foreach (int count, counts) { foreach (bool transaction, transactions) { //krazy:exclude=foreach QTest::newRow(QString::fromLatin1("%1-%2").arg(count).arg(transaction ? QLatin1String("trans") : QLatin1String("notrans")).toLatin1().constData()) << count << transaction; } } } void createCollections() { QFETCH(int, count); QFETCH(bool, useTransaction); - const Collection parent(collectionIdFromPath(QLatin1String("res3"))); + const Collection parent(AkonadiTest::collectionIdFromPath(QLatin1String("res3"))); QVERIFY(parent.isValid()); static int index = 0; Job *lastJob = 0; QBENCHMARK { if (useTransaction) { lastJob = new TransactionBeginJob(this); } for (int i = 0; i < count; ++i) { Collection col; col.setParentCollection(parent); col.setName(QLatin1String("col") + QString::number(++index)); lastJob = new CollectionCreateJob(col, this); } if (useTransaction) { lastJob = new TransactionCommitJob(this); } AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*)), 15000); } } }; QTEST_AKONADIMAIN(CollectionCreator) #include "collectioncreator.moc" diff --git a/autotests/libs/collectionjobtest.cpp b/autotests/libs/collectionjobtest.cpp index c388d1833..702c01d9d 100644 --- a/autotests/libs/collectionjobtest.cpp +++ b/autotests/libs/collectionjobtest.cpp @@ -1,906 +1,905 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "collectionjobtest.h" #include #include -#include "test_utils.h" #include "testattribute.h" #include "agentmanager.h" #include "agentinstance.h" #include "attributefactory.h" #include "cachepolicy.h" #include "collection.h" #include "collectioncreatejob.h" #include "collectiondeletejob.h" #include "collectionfetchjob.h" #include "collectionmodifyjob.h" #include "collectionstatistics.h" #include "collectionstatisticsjob.h" #include "collectionutils.h" #include "control.h" #include "item.h" #include "resourceselectjob_p.h" #include "collectionfetchscope.h" using namespace Akonadi; QTEST_AKONADIMAIN(CollectionJobTest) void CollectionJobTest::initTestCase() { qRegisterMetaType(); AttributeFactory::registerAttribute(); AkonadiTest::checkTestIsIsolated(); Control::start(); AkonadiTest::setAllResourcesOffline(); } static Collection findCol(const Collection::List &list, const QString &name) { foreach (const Collection &col, list) if (col.name() == name) { return col; } return Collection(); } // list compare which ignores the order template static void compareLists(const QList &l1, const QList &l2) { QCOMPARE(l1.count(), l2.count()); foreach (const T &entry, l1) { QVERIFY(l2.contains(entry)); } } template static void compareLists(const QVector &l1, const QVector &l2) { QCOMPARE(l1.count(), l2.count()); foreach (const T &entry, l1) { QVERIFY(l2.contains(entry)); } } template static T *extractAttribute(QList attrs) { T dummy; foreach (Attribute *attr, attrs) { if (attr->type() == dummy.type()) { return dynamic_cast(attr); } } return 0; } static Collection::Id res1ColId = 6; // -1; static Collection::Id res2ColId = 7; //-1; static Collection::Id res3ColId = -1; static Collection::Id searchColId = -1; void CollectionJobTest::testTopLevelList() { // non-recursive top-level list CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel); AKVERIFYEXEC(job); Collection::List list = job->collections(); // check if everything is there and has the correct types and attributes QCOMPARE(list.count(), 4); Collection col; col = findCol(list, QStringLiteral("res1")); QVERIFY(col.isValid()); res1ColId = col.id(); // for the next test QVERIFY(res1ColId > 0); QVERIFY(CollectionUtils::isResource(col)); QCOMPARE(col.parentCollection(), Collection::root()); QCOMPARE(col.resource(), QStringLiteral("akonadi_knut_resource_0")); QVERIFY(findCol(list, QStringLiteral("res2")).isValid()); res2ColId = findCol(list, QStringLiteral("res2")).id(); QVERIFY(res2ColId > 0); QVERIFY(findCol(list, QStringLiteral("res3")).isValid()); res3ColId = findCol(list, QStringLiteral("res3")).id(); QVERIFY(res3ColId > 0); col = findCol(list, QStringLiteral("Search")); searchColId = col.id(); QVERIFY(col.isValid()); QVERIFY(CollectionUtils::isVirtualParent(col)); QCOMPARE(col.resource(), QStringLiteral("akonadi_search_resource")); } void CollectionJobTest::testFolderList() { // recursive list of physical folders CollectionFetchJob *job = new CollectionFetchJob(Collection(res1ColId), CollectionFetchJob::Recursive); QSignalSpy spy(job, &CollectionFetchJob::collectionsReceived); QVERIFY(spy.isValid()); AKVERIFYEXEC(job); Collection::List list = job->collections(); int count = 0; for (int i = 0; i < spy.count(); ++i) { Collection::List l = spy[i][0].value(); for (int j = 0; j < l.count(); ++j) { QVERIFY(list.count() > count + j); QCOMPARE(list[count + j].id(), l[j].id()); } count += l.count(); } QCOMPARE(count, list.count()); // check if everything is there QCOMPARE(list.count(), 4); Collection col; QStringList contentTypes; col = findCol(list, QStringLiteral("foo")); QVERIFY(col.isValid()); QCOMPARE(col.parentCollection().id(), res1ColId); QVERIFY(CollectionUtils::isFolder(col)); contentTypes << QStringLiteral("message/rfc822") << QStringLiteral("text/calendar") << QStringLiteral("text/directory") << QStringLiteral("application/octet-stream") << QStringLiteral("inode/directory"); compareLists(col.contentMimeTypes(), contentTypes); QVERIFY(findCol(list, QStringLiteral("bar")).isValid()); QCOMPARE(findCol(list, QStringLiteral("bar")).parentCollection(), col); QVERIFY(findCol(list, QStringLiteral("bla")).isValid()); } class ResultSignalTester : public QObject { Q_OBJECT public: QStringList receivedSignals; public Q_SLOTS: void onCollectionsReceived(const Akonadi::Collection::List &) { receivedSignals << QStringLiteral("collectionsReceived"); } void onCollectionRetrievalDone(KJob *) { receivedSignals << QStringLiteral("result"); } }; void CollectionJobTest::testSignalOrder() { Akonadi::Collection::List toFetch; toFetch << Collection(res1ColId); toFetch << Collection(res2ColId); CollectionFetchJob *job = new CollectionFetchJob(toFetch, CollectionFetchJob::Recursive); ResultSignalTester spy; connect(job, &CollectionFetchJob::collectionsReceived, &spy, &ResultSignalTester::onCollectionsReceived); connect(job, &KJob::result, &spy, &ResultSignalTester::onCollectionRetrievalDone); AKVERIFYEXEC(job); QCOMPARE(spy.receivedSignals.size(), 2); QCOMPARE(spy.receivedSignals.at(0), QStringLiteral("collectionsReceived")); QCOMPARE(spy.receivedSignals.at(1), QStringLiteral("result")); } void CollectionJobTest::testNonRecursiveFolderList() { CollectionFetchJob *job = new CollectionFetchJob(Collection(res1ColId), CollectionFetchJob::Base); AKVERIFYEXEC(job); Collection::List list = job->collections(); QCOMPARE(list.count(), 1); QVERIFY(findCol(list, QStringLiteral("res1")).isValid()); } void CollectionJobTest::testEmptyFolderList() { CollectionFetchJob *job = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel); AKVERIFYEXEC(job); Collection::List list = job->collections(); QCOMPARE(list.count(), 0); } void CollectionJobTest::testSearchFolderList() { CollectionFetchJob *job = new CollectionFetchJob(Collection(searchColId), CollectionFetchJob::FirstLevel); AKVERIFYEXEC(job); Collection::List list = job->collections(); QCOMPARE(list.count(), 0); } void CollectionJobTest::testResourceFolderList() { // non-existing resource CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel); job->fetchScope().setResource(QStringLiteral("i_dont_exist")); QVERIFY(!job->exec()); // recursive listing of all collections of an existing resource job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive); job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(job); Collection::List list = job->collections(); QCOMPARE(list.count(), 5); QVERIFY(findCol(list, QStringLiteral("res1")).isValid()); QVERIFY(findCol(list, QStringLiteral("foo")).isValid()); QVERIFY(findCol(list, QStringLiteral("bar")).isValid()); QVERIFY(findCol(list, QStringLiteral("bla")).isValid()); int fooId = findCol(list, QStringLiteral("foo")).id(); // limited listing of a resource job = new CollectionFetchJob(Collection(fooId), CollectionFetchJob::Recursive); job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(job); list = job->collections(); QCOMPARE(list.count(), 3); QVERIFY(findCol(list, QStringLiteral("bar")).isValid()); QVERIFY(findCol(list, QStringLiteral("bla")).isValid()); } void CollectionJobTest::testMimeTypeFilter() { CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive); job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("message/rfc822")); AKVERIFYEXEC(job); Collection::List list = job->collections(); QCOMPARE(list.count(), 2); QVERIFY(findCol(list, QStringLiteral("res1")).isValid()); QVERIFY(findCol(list, QStringLiteral("foo")).isValid()); int fooId = findCol(list, QStringLiteral("foo")).id(); // limited listing of a resource job = new CollectionFetchJob(Collection(fooId), CollectionFetchJob::Recursive); job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("message/rfc822")); AKVERIFYEXEC(job); list = job->collections(); QCOMPARE(list.count(), 0); // non-existing mimetype job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("something/non-existing")); AKVERIFYEXEC(job); QCOMPARE(job->collections().size(), 0); } void CollectionJobTest::testCreateDeleteFolder_data() { QTest::addColumn("collection"); QTest::addColumn("creatable"); Collection col; QTest::newRow("empty") << col << false; col.setName(QStringLiteral("new folder")); col.parentCollection().setId(res3ColId); QTest::newRow("simple") << col << true; col.parentCollection().setId(res3ColId); col.setName(QStringLiteral("foo")); QTest::newRow("existing in different resource") << col << true; col.setName(QStringLiteral("mail folder")); QStringList mimeTypes; mimeTypes << QStringLiteral("inode/directory") << QStringLiteral("message/rfc822"); col.setContentMimeTypes(mimeTypes); col.setRemoteId(QStringLiteral("remote id")); CachePolicy policy; policy.setInheritFromParent(false); policy.setIntervalCheckTime(60); policy.setLocalParts({QStringLiteral("PLD:ENVELOPE")}); policy.setSyncOnDemand(true); policy.setCacheTimeout(120); col.setCachePolicy(policy); QTest::newRow("complex") << col << true; col = Collection(); col.setName(QStringLiteral("New Folder")); col.parentCollection().setId(searchColId); QTest::newRow("search folder") << col << false; col.parentCollection().setId(res2ColId); col.setName(QStringLiteral("foo2")); QTest::newRow("already existing") << col << false; col.parentCollection().setId(res2ColId); // Sibling of collection 'foo2' col.setName(QStringLiteral("foo2 ")); QTest::newRow("name of an sibling with an additional ending space") << col << true; col.setName(QStringLiteral("Bla")); col.parentCollection().setId(2); QTest::newRow("already existing with different case") << col << true; CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res2/foo2"), this); AKVERIFYEXEC(resolver); col.parentCollection().setId(resolver->collection()); col.setName(QStringLiteral("new folder")); QTest::newRow("parent noinferior") << col << false; col.parentCollection().setId(INT_MAX); QTest::newRow("missing parent") << col << false; col = Collection(); col.setName(QStringLiteral("rid parent")); col.parentCollection().setRemoteId(QStringLiteral("8")); QTest::newRow("rid parent") << col << false; // missing resource context } void CollectionJobTest::testCreateDeleteFolder() { QFETCH(Collection, collection); QFETCH(bool, creatable); CollectionCreateJob *createJob = new CollectionCreateJob(collection, this); QCOMPARE(createJob->exec(), creatable); if (!creatable) { return; } Collection createdCol = createJob->collection(); QVERIFY(createdCol.isValid()); QCOMPARE(createdCol.name(), collection.name()); QCOMPARE(createdCol.parentCollection(), collection.parentCollection()); QCOMPARE(createdCol.remoteId(), collection.remoteId()); QCOMPARE(createdCol.cachePolicy(), collection.cachePolicy()); CollectionFetchJob *listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::FirstLevel, this); AKVERIFYEXEC(listJob); Collection listedCol = findCol(listJob->collections(), collection.name()); QCOMPARE(listedCol, createdCol); QCOMPARE(listedCol.remoteId(), collection.remoteId()); QCOMPARE(listedCol.cachePolicy(), collection.cachePolicy()); // fetch parent to compare inherited collection properties Collection parentCol = Collection::root(); if (collection.parentCollection().isValid()) { CollectionFetchJob *listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::Base, this); AKVERIFYEXEC(listJob); QCOMPARE(listJob->collections().count(), 1); parentCol = listJob->collections().first(); } if (collection.contentMimeTypes().isEmpty()) { compareLists(listedCol.contentMimeTypes(), parentCol.contentMimeTypes()); } else { compareLists(listedCol.contentMimeTypes(), collection.contentMimeTypes()); } if (collection.resource().isEmpty()) { QCOMPARE(listedCol.resource(), parentCol.resource()); } else { QCOMPARE(listedCol.resource(), collection.resource()); } CollectionDeleteJob *delJob = new CollectionDeleteJob(createdCol, this); AKVERIFYEXEC(delJob); listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::FirstLevel, this); AKVERIFYEXEC(listJob); QVERIFY(!findCol(listJob->collections(), collection.name()).isValid()); } void CollectionJobTest::testIllegalDeleteFolder() { // non-existing folder CollectionDeleteJob *del = new CollectionDeleteJob(Collection(INT_MAX), this); QVERIFY(!del->exec()); // root del = new CollectionDeleteJob(Collection::root(), this); QVERIFY(!del->exec()); } void CollectionJobTest::testStatistics() { // empty folder CollectionStatisticsJob *statistics = new CollectionStatisticsJob(Collection(res1ColId), this); AKVERIFYEXEC(statistics); CollectionStatistics s = statistics->statistics(); QCOMPARE(s.count(), 0ll); QCOMPARE(s.unreadCount(), 0ll); // folder with attributes and content CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1/foo"), this); AKVERIFYEXEC(resolver); statistics = new CollectionStatisticsJob(Collection(resolver->collection()), this); AKVERIFYEXEC(statistics); s = statistics->statistics(); QCOMPARE(s.count(), 15ll); QCOMPARE(s.unreadCount(), 14ll); } void CollectionJobTest::testModify_data() { QTest::addColumn("uid"); QTest::addColumn("rid"); - QTest::newRow("uid") << collectionIdFromPath(QStringLiteral("res1/foo")) << QString(); + QTest::newRow("uid") << AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo")) << QString(); QTest::newRow("rid") << -1ll << QStringLiteral("10"); } #define RESET_COLLECTION_ID \ col.setId( uid ); \ if ( !rid.isEmpty() ) col.setRemoteId( rid ) void CollectionJobTest::testModify() { QFETCH(qint64, uid); QFETCH(QString, rid); if (!rid.isEmpty()) { ResourceSelectJob *rjob = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(rjob); } const QStringList reference = { QStringLiteral("text/calendar"), QStringLiteral("text/directory"), QStringLiteral("message/rfc822"), QStringLiteral("application/octet-stream"), QStringLiteral("inode/directory") }; Collection col; RESET_COLLECTION_ID; // test noop modify CollectionModifyJob *mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); CollectionFetchJob *ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 1); col = ljob->collections().first(); compareLists(col.contentMimeTypes(), reference); // test clearing content types RESET_COLLECTION_ID; col.setContentMimeTypes(QStringList()); mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 1); col = ljob->collections().first(); QVERIFY(col.contentMimeTypes().isEmpty()); // test setting contnet types RESET_COLLECTION_ID; col.setContentMimeTypes(reference); mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 1); col = ljob->collections().first(); compareLists(col.contentMimeTypes(), reference); // add attribute RESET_COLLECTION_ID; col.attribute(Collection::AddIfMissing)->data = "new"; mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(ljob); QVERIFY(ljob->collections().first().hasAttribute()); QCOMPARE(ljob->collections().first().attribute()->data, QByteArray("new")); // modify existing attribute RESET_COLLECTION_ID; col.attribute()->data = "modified"; mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(ljob); QVERIFY(ljob->collections().first().hasAttribute()); QCOMPARE(ljob->collections().first().attribute()->data, QByteArray("modified")); // renaming RESET_COLLECTION_ID; col.setName(QStringLiteral("foo (renamed)")); mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 1); col = ljob->collections().first(); QCOMPARE(col.name(), QStringLiteral("foo (renamed)")); RESET_COLLECTION_ID; col.setName(QStringLiteral("foo")); mod = new CollectionModifyJob(col, this); AKVERIFYEXEC(mod); } #undef RESET_COLLECTION_ID void CollectionJobTest::testIllegalModify() { // non-existing collection Collection col(INT_MAX); col.parentCollection().setId(res1ColId); CollectionModifyJob *mod = new CollectionModifyJob(col, this); QVERIFY(!mod->exec()); // rename to already existing name col = Collection(res1ColId); col.setName(QStringLiteral("res2")); mod = new CollectionModifyJob(col, this); QVERIFY(!mod->exec()); } void CollectionJobTest::testUtf8CollectionName_data() { QTest::addColumn("folderName"); QTest::newRow("Umlaut") << QString::fromUtf8("ä"); QTest::newRow("Garbage") << QString::fromUtf8("đ→³}đþøæſð"); QTest::newRow("Utf8") << QString::fromUtf8("日本語"); } void CollectionJobTest::testUtf8CollectionName() { QFETCH(QString, folderName); // create collection Collection col; col.parentCollection().setId(res3ColId); col.setName(folderName); CollectionCreateJob *create = new CollectionCreateJob(col, this); AKVERIFYEXEC(create); col = create->collection(); QVERIFY(col.isValid()); QCOMPARE(col.name(), folderName); // list parent CollectionFetchJob *list = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::Recursive, this); AKVERIFYEXEC(list); QCOMPARE(list->collections().count(), 1); QCOMPARE(list->collections().first(), col); QCOMPARE(list->collections().first().name(), col.name()); // modify collection col.setContentMimeTypes( { QStringLiteral("message/rfc822") } ); CollectionModifyJob *modify = new CollectionModifyJob(col, this); AKVERIFYEXEC(modify); // collection statistics CollectionStatisticsJob *statistics = new CollectionStatisticsJob(col, this); AKVERIFYEXEC(statistics); CollectionStatistics s = statistics->statistics(); QCOMPARE(s.count(), 0ll); QCOMPARE(s.unreadCount(), 0ll); // delete collection CollectionDeleteJob *del = new CollectionDeleteJob(col, this); AKVERIFYEXEC(del); } void CollectionJobTest::testMultiList() { Collection::List req; req << Collection(res1ColId) << Collection(res2ColId); CollectionFetchJob *job = new CollectionFetchJob(req, this); AKVERIFYEXEC(job); Collection::List res; res = job->collections(); compareLists(res, req); } void CollectionJobTest::testMultiListInvalid() { Collection::List req; req << Collection(res1ColId) << Collection(1234567) << Collection(res2ColId); CollectionFetchJob *job = new CollectionFetchJob(req, this); QVERIFY(!job->exec()); // not all available collections are fetched QVERIFY(job->collections().count() != 2); job = new CollectionFetchJob(req, this); job->fetchScope().setIgnoreRetrievalErrors(true); QVERIFY(!job->exec()); Collection::List res; res = job->collections(); req = Collection::List() << Collection(res1ColId) << Collection(res2ColId); compareLists(res, req); } void CollectionJobTest::testRecursiveMultiList() { Akonadi::Collection::List toFetch; toFetch << Collection(res1ColId); toFetch << Collection(res2ColId); CollectionFetchJob *job = new CollectionFetchJob(toFetch, CollectionFetchJob::Recursive); QSignalSpy spy(job, &CollectionFetchJob::collectionsReceived); QVERIFY(spy.isValid()); AKVERIFYEXEC(job); Collection::List list = job->collections(); int count = 0; for (int i = 0; i < spy.count(); ++i) { Collection::List l = spy[i][0].value(); for (int j = 0; j < l.count(); ++j) { QVERIFY(list.count() > count + j); QCOMPARE(list[count + j].id(), l[j].id()); } count += l.count(); } QCOMPARE(count, list.count()); // check if everything is there QCOMPARE(list.count(), 4 + 2); QVERIFY(findCol(list, QStringLiteral("foo")).isValid()); QVERIFY(findCol(list, QStringLiteral("bar")).isValid()); QVERIFY(findCol(list, QStringLiteral("bla")).isValid()); //There are two bla folders, but we only check for one. QVERIFY(findCol(list, QStringLiteral("foo2")).isValid()); QVERIFY(findCol(list, QStringLiteral("space folder")).isValid()); } void CollectionJobTest::testNonOverlappingRootList() { Akonadi::Collection::List toFetch; toFetch << Collection(res1ColId); toFetch << Collection(res2ColId); CollectionFetchJob *job = new CollectionFetchJob(toFetch, CollectionFetchJob::NonOverlappingRoots); QSignalSpy spy(job, &CollectionFetchJob::collectionsReceived); QVERIFY(spy.isValid()); AKVERIFYEXEC(job); Collection::List list = job->collections(); int count = 0; for (int i = 0; i < spy.count(); ++i) { Collection::List l = spy[i][0].value(); for (int j = 0; j < l.count(); ++j) { QVERIFY(list.count() > count + j); QCOMPARE(list[count + j].id(), l[j].id()); } count += l.count(); } QCOMPARE(count, list.count()); // check if everything is there QCOMPARE(list.count(), 2); QVERIFY(findCol(list, QStringLiteral("res1")).isValid()); QVERIFY(findCol(list, QStringLiteral("res2")).isValid()); } void CollectionJobTest::testRidFetch() { Collection col; col.setRemoteId(QStringLiteral("10")); CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base, this); job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(job); QCOMPARE(job->collections().count(), 1); col = job->collections().first(); QVERIFY(col.isValid()); QCOMPARE(col.remoteId(), QString::fromLatin1("10")); } void CollectionJobTest::testRidCreateDelete_data() { QTest::addColumn("remoteId"); QTest::newRow("ASCII") << QString::fromUtf8("MY REMOTE ID"); QTest::newRow("LATIN1") << QString::fromUtf8("MY REMÖTE ID"); QTest::newRow("UTF8") << QString::fromUtf8("MY REMOTE 検索表"); } void CollectionJobTest::testRidCreateDelete() { QFETCH(QString, remoteId); Collection collection; collection.setName(QStringLiteral("rid create")); collection.parentCollection().setRemoteId(QStringLiteral("8")); collection.setRemoteId(remoteId); ResourceSelectJob *resSel = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_2")); AKVERIFYEXEC(resSel); CollectionCreateJob *createJob = new CollectionCreateJob(collection, this); AKVERIFYEXEC(createJob); Collection createdCol = createJob->collection(); QVERIFY(createdCol.isValid()); QCOMPARE(createdCol.name(), collection.name()); CollectionFetchJob *listJob = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel, this); AKVERIFYEXEC(listJob); Collection listedCol = findCol(listJob->collections(), collection.name()); QCOMPARE(listedCol, createdCol); QCOMPARE(listedCol.name(), collection.name()); QVERIFY(!collection.isValid()); CollectionDeleteJob *delJob = new CollectionDeleteJob(collection, this); AKVERIFYEXEC(delJob); listJob = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel, this); AKVERIFYEXEC(listJob); QVERIFY(!findCol(listJob->collections(), collection.name()).isValid()); } void CollectionJobTest::testAncestorRetrieval() { Collection col; col.setRemoteId(QStringLiteral("10")); CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base, this); job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0")); job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); AKVERIFYEXEC(job); QCOMPARE(job->collections().count(), 1); col = job->collections().first(); QVERIFY(col.isValid()); QVERIFY(col.parentCollection().isValid()); QCOMPARE(col.parentCollection().remoteId(), QStringLiteral("6")); QCOMPARE(col.parentCollection().parentCollection(), Collection::root()); ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0"), this); AKVERIFYEXEC(select); Collection col2(col); col2.setId(-1); // make it invalid but keep the ancestor chain job = new CollectionFetchJob(col2, CollectionFetchJob::Base, this); AKVERIFYEXEC(job); QCOMPARE(job->collections().count(), 1); col2 = job->collections().first(); QVERIFY(col2.isValid()); QCOMPARE(col, col2); } void CollectionJobTest::testAncestorAttributeRetrieval() { Akonadi::Collection baseCol; { baseCol.setParentCollection(Akonadi::Collection(res1ColId)); baseCol.setName(QStringLiteral("base")); baseCol.attribute(Collection::AddIfMissing)->data = "new"; Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); AKVERIFYEXEC(create); baseCol = create->collection(); } { Akonadi::Collection col; col.setParentCollection(baseCol); col.setName(QStringLiteral("enabled")); Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); AKVERIFYEXEC(create); CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); job->fetchScope().ancestorFetchScope().setFetchIdOnly(false); job->fetchScope().ancestorFetchScope().fetchAttribute(); AKVERIFYEXEC(job); Akonadi::Collection result = job->collections().first(); QCOMPARE(result.parentCollection().hasAttribute(), true); } //Cleanup CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); AKVERIFYEXEC(deleteJob); } void CollectionJobTest::testListPreference() { Akonadi::Collection baseCol; { baseCol.setParentCollection(Akonadi::Collection(res1ColId)); baseCol.setName(QStringLiteral("base")); Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); AKVERIFYEXEC(create); baseCol = create->collection(); } { Akonadi::Collection col; col.setParentCollection(baseCol); col.setEnabled(true); col.setName(QStringLiteral("enabled")); Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); AKVERIFYEXEC(create); CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); AKVERIFYEXEC(job); Akonadi::Collection result = job->collections().first(); QCOMPARE(result.enabled(), true); QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListDefault); QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListDefault); QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListDefault); } { Akonadi::Collection col; col.setParentCollection(baseCol); col.setName(QStringLiteral("disabledPref")); col.setEnabled(true); col.setLocalListPreference(Collection::ListDisplay, Collection::ListDisabled); col.setLocalListPreference(Collection::ListSync, Collection::ListDisabled); col.setLocalListPreference(Collection::ListIndex, Collection::ListDisabled); Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); AKVERIFYEXEC(create); CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); AKVERIFYEXEC(job); Akonadi::Collection result = job->collections().first(); QCOMPARE(result.enabled(), true); QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListDisabled); QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListDisabled); QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListDisabled); } { Akonadi::Collection col; col.setParentCollection(baseCol); col.setName(QStringLiteral("enabledPref")); col.setEnabled(false); col.setLocalListPreference(Collection::ListDisplay, Collection::ListEnabled); col.setLocalListPreference(Collection::ListSync, Collection::ListEnabled); col.setLocalListPreference(Collection::ListIndex, Collection::ListEnabled); Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); AKVERIFYEXEC(create); CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); AKVERIFYEXEC(job); Akonadi::Collection result = job->collections().first(); QCOMPARE(result.enabled(), false); QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListEnabled); QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListEnabled); QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListEnabled); } //Check list filter { CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); job->fetchScope().setListFilter(CollectionFetchScope::Display); AKVERIFYEXEC(job); QCOMPARE(job->collections().size(), 2); } { CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); job->fetchScope().setListFilter(CollectionFetchScope::Sync); AKVERIFYEXEC(job); QCOMPARE(job->collections().size(), 2); } { CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); job->fetchScope().setListFilter(CollectionFetchScope::Index); AKVERIFYEXEC(job); QCOMPARE(job->collections().size(), 2); } { CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); job->fetchScope().setListFilter(CollectionFetchScope::Enabled); AKVERIFYEXEC(job); QCOMPARE(job->collections().size(), 2); } //Cleanup CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); AKVERIFYEXEC(deleteJob); } #include "collectionjobtest.moc" diff --git a/autotests/libs/collectionmodifytest.cpp b/autotests/libs/collectionmodifytest.cpp index f0b3520f0..d1c6deb20 100644 --- a/autotests/libs/collectionmodifytest.cpp +++ b/autotests/libs/collectionmodifytest.cpp @@ -1,81 +1,81 @@ /* * Copyright 2015 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ -#include "test_utils.h" #include "collectioncreatejob.h" #include "collectionfetchjob.h" #include "collectionmodifyjob.h" #include "collectiondeletejob.h" #include "entitydisplayattribute.h" +#include "qtest_akonadi.h" using namespace Akonadi; class CollectionModifyTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testModifyCollection() { Collection col; col.setName(QLatin1String("test_collection")); col.setContentMimeTypes({ Collection::mimeType() }); - col.setParentCollection(Collection(collectionIdFromPath(QLatin1String("res1")))); + col.setParentCollection(Collection(AkonadiTest::collectionIdFromPath(QLatin1String("res1")))); col.setRights(Collection::AllRights); CollectionCreateJob *cj = new CollectionCreateJob(col, this); AKVERIFYEXEC(cj); col = cj->collection(); QVERIFY(col.isValid()); auto attr = col.attribute(Collection::AddIfMissing); attr->setDisplayName(QStringLiteral("Test Collection")); col.setContentMimeTypes({ Collection::mimeType(), QLatin1String("application/octet-stream") }); CollectionModifyJob *mj = new CollectionModifyJob(col, this); AKVERIFYEXEC(mj); CollectionFetchJob *fj = new CollectionFetchJob(col, CollectionFetchJob::Base); AKVERIFYEXEC(fj); QCOMPARE(fj->collections().count(), 1); const Collection actual = fj->collections().at(0); QCOMPARE(actual.id(), col.id()); QCOMPARE(actual.name(), col.name()); QCOMPARE(actual.displayName(), col.displayName()); QCOMPARE(actual.contentMimeTypes(), col.contentMimeTypes()); QCOMPARE(actual.parentCollection(), col.parentCollection()); QCOMPARE(actual.rights(), col.rights()); CollectionDeleteJob *dj = new CollectionDeleteJob(col, this); AKVERIFYEXEC(dj); } }; QTEST_AKONADIMAIN(CollectionModifyTest) #include "collectionmodifytest.moc" diff --git a/autotests/libs/collectionmovetest.cpp b/autotests/libs/collectionmovetest.cpp index 0a1bfe78e..b2fc7e005 100644 --- a/autotests/libs/collectionmovetest.cpp +++ b/autotests/libs/collectionmovetest.cpp @@ -1,151 +1,150 @@ /* Copyright (c) 2006, 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" - +#include "qtest_akonadi.h" #include "collection.h" #include "collectionfetchjob.h" #include "collectionmovejob.h" #include "item.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include using namespace Akonadi; class CollectionMoveTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testIllegalMove_data() { QTest::addColumn("source"); QTest::addColumn("destination"); - const Collection res1(collectionIdFromPath(QStringLiteral("res1"))); - const Collection res1foo(collectionIdFromPath(QStringLiteral("res1/foo"))); - const Collection res1bla(collectionIdFromPath(QStringLiteral("res1/foo/bar/bla"))); + const Collection res1(AkonadiTest::collectionIdFromPath(QStringLiteral("res1"))); + const Collection res1foo(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection res1bla(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bar/bla"))); QTest::newRow("non-existing-target") << res1 << Collection(INT_MAX); QTest::newRow("root") << Collection::root() << res1; QTest::newRow("move-into-child") << res1 << res1foo; QTest::newRow("same-name-in-target") << res1bla << res1foo; QTest::newRow("non-existing-source") << Collection(INT_MAX) << res1; } void testIllegalMove() { QFETCH(Collection, source); QFETCH(Collection, destination); QVERIFY(source.isValid()); QVERIFY(destination.isValid()); CollectionMoveJob *mod = new CollectionMoveJob(source, destination, this); QVERIFY(!mod->exec()); } void testMove_data() { QTest::addColumn("source"); QTest::addColumn("destination"); QTest::addColumn("crossResource"); - QTest::newRow("inter-resource") << Collection(collectionIdFromPath(QStringLiteral("res1"))) - << Collection(collectionIdFromPath(QStringLiteral("res2"))) + QTest::newRow("inter-resource") << Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1"))) + << Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2"))) << true; - QTest::newRow("intra-resource") << Collection(collectionIdFromPath(QStringLiteral("res1/foo/bla"))) - << Collection(collectionIdFromPath(QStringLiteral("res1/foo/bar/bla"))) + QTest::newRow("intra-resource") << Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bla"))) + << Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bar/bla"))) << false; } // TODO: test signals void testMove() { QFETCH(Collection, source); QFETCH(Collection, destination); QFETCH(bool, crossResource); QVERIFY(source.isValid()); QVERIFY(destination.isValid()); CollectionFetchJob *fetch = new CollectionFetchJob(source, CollectionFetchJob::Base, this); AKVERIFYEXEC(fetch); QCOMPARE(fetch->collections().count(), 1); source = fetch->collections().first(); // obtain reference listing fetch = new CollectionFetchJob(source, CollectionFetchJob::Recursive); AKVERIFYEXEC(fetch); QHash referenceData; foreach (const Collection &c, fetch->collections()) { ItemFetchJob *job = new ItemFetchJob(c, this); AKVERIFYEXEC(job); referenceData.insert(c, job->items()); } // move collection CollectionMoveJob *mod = new CollectionMoveJob(source, destination, this); AKVERIFYEXEC(mod); // check if source was modified correctly CollectionFetchJob *ljob = new CollectionFetchJob(source, CollectionFetchJob::Base); AKVERIFYEXEC(ljob); Collection::List list = ljob->collections(); QCOMPARE(list.count(), 1); Collection col = list.first(); QCOMPARE(col.name(), source.name()); QCOMPARE(col.parentCollection(), destination); // list destination and check if everything is still there ljob = new CollectionFetchJob(destination, CollectionFetchJob::Recursive); AKVERIFYEXEC(ljob); list = ljob->collections(); QVERIFY(list.count() >= referenceData.count()); for (QHash::ConstIterator it = referenceData.constBegin(); it != referenceData.constEnd(); ++it) { QVERIFY(list.contains(it.key())); if (crossResource) { QVERIFY(list[list.indexOf(it.key())].resource() != it.key().resource()); } else { QCOMPARE(list[list.indexOf(it.key())].resource(), it.key().resource()); } ItemFetchJob *job = new ItemFetchJob(it.key(), this); job->fetchScope().fetchFullPayload(); AKVERIFYEXEC(job); QCOMPARE(job->items().count(), it.value().count()); foreach (const Item &item, job->items()) { QVERIFY(it.value().contains(item)); QVERIFY(item.hasPayload()); } } // cleanup mod = new CollectionMoveJob(col, source.parentCollection(), this); AKVERIFYEXEC(mod); } }; QTEST_AKONADIMAIN(CollectionMoveTest) #include "collectionmovetest.moc" diff --git a/autotests/libs/collectionsynctest.cpp b/autotests/libs/collectionsynctest.cpp index 26ae9121b..586e4d722 100644 --- a/autotests/libs/collectionsynctest.cpp +++ b/autotests/libs/collectionsynctest.cpp @@ -1,442 +1,440 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" - #include "agentmanager.h" #include "agentinstance.h" #include "control.h" #include "collection.h" #include "collectionfetchjob.h" #include "collectionfetchscope.h" #include "collectiondeletejob.h" #include "collectionmodifyjob.h" #include "entitydisplayattribute.h" #include "collectionsync_p.h" #include "qtest_akonadi.h" #include "resourceselectjob_p.h" #include #include #include using namespace Akonadi; class CollectionSyncTest : public QObject { Q_OBJECT private: Collection::List fetchCollections(const QString &res) { CollectionFetchJob *fetch = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); fetch->fetchScope().setResource(res); fetch->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); if (!fetch->exec()) { qWarning() << "CollectionFetchJob failed!"; return Collection::List(); } return fetch->collections(); } void makeTestData() { QTest::addColumn("hierarchicalRIDs"); QTest::addColumn("resource"); QTest::newRow("akonadi_knut_resource_0 global RID") << false << "akonadi_knut_resource_0"; QTest::newRow("akonadi_knut_resource_1 global RID") << false << "akonadi_knut_resource_1"; QTest::newRow("akonadi_knut_resource_2 global RID") << false << "akonadi_knut_resource_2"; QTest::newRow("akonadi_knut_resource_0 hierarchical RID") << true << "akonadi_knut_resource_0"; QTest::newRow("akonadi_knut_resource_1 hierarchical RID") << true << "akonadi_knut_resource_1"; QTest::newRow("akonadi_knut_resource_2 hierarchical RID") << true << "akonadi_knut_resource_2"; } Collection createCollection(const QString &name, const QString &remoteId, const Collection &parent) { Collection c; c.setName(name); c.setRemoteId(remoteId); c.setParentCollection(parent); c.setResource(QStringLiteral("akonadi_knut_resource_0")); c.setContentMimeTypes(QStringList() << Collection::mimeType()); return c; } Collection::List prepareBenchmark() { Collection::List collections = fetchCollections(QStringLiteral("akonadi_knut_resource_0")); ResourceSelectJob *resJob = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); Q_ASSERT(resJob->exec()); Collection root; Q_FOREACH (const Collection &col, collections) { if (col.parentCollection() == Collection::root()) { root = col; break; } } Q_ASSERT(root.isValid()); // we must build on top of existing collections, because only resource is // allowed to create top-level collection Collection::List baseCollections; for (int i = 0; i < 20; ++i) { baseCollections << createCollection(QStringLiteral("Base Col %1").arg(i), QStringLiteral("/baseCol%1").arg(i), root); } collections += baseCollections; const Collection shared = createCollection(QStringLiteral("Shared collections"), QStringLiteral("/shared"), root); baseCollections << shared; collections << shared; for (int i = 0; i < 10000; ++i) { const Collection col = createCollection(QStringLiteral("Shared Col %1").arg(i), QStringLiteral("/shared%1").arg(i), shared); collections << col; for (int j = 0; j < 6; ++j) { collections << createCollection(QStringLiteral("Shared Subcol %1-%2").arg(i).arg(j), QStringLiteral("/shared%1-%2").arg(i).arg(j), col); } } return collections; } CollectionSync *prepareBenchmarkSyncer(const Collection::List &collections) { CollectionSync *syncer = new CollectionSync(QStringLiteral("akonadi_knut_resource_0")); connect(syncer, SIGNAL(percent(KJob*,ulong)), this, SLOT(syncBenchmarkProgress(KJob*,ulong))); syncer->setHierarchicalRemoteIds(false); syncer->setRemoteCollections(collections); return syncer; } void cleanupBenchmark(const Collection::List &collections) { Collection::List baseCols; for (const Collection &col : collections) { if (col.remoteId().startsWith(QLatin1String("/baseCol")) || col.remoteId() == QLatin1String("/shared")) { baseCols << col; } } for (const Collection &col : qAsConst(baseCols)) { CollectionDeleteJob *del = new CollectionDeleteJob(col); AKVERIFYEXEC(del); } } public Q_SLOTS: void syncBenchmarkProgress(KJob *job, ulong percent) { Q_UNUSED(job); qDebug() << "CollectionSync progress:" << percent << "%"; } private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AkonadiTest::setAllResourcesOffline(); qRegisterMetaType(); } void testFullSync_data() { makeTestData(); } void testFullSync() { QFETCH(bool, hierarchicalRIDs); QFETCH(QString, resource); Collection::List origCols = fetchCollections(resource); QVERIFY(!origCols.isEmpty()); CollectionSync *syncer = new CollectionSync(resource, this); syncer->setHierarchicalRemoteIds(hierarchicalRIDs); syncer->setRemoteCollections(origCols); AKVERIFYEXEC(syncer); Collection::List resultCols = fetchCollections(resource); QCOMPARE(resultCols.count(), origCols.count()); } void testFullStreamingSync_data() { makeTestData(); } void testFullStreamingSync() { QFETCH(bool, hierarchicalRIDs); QFETCH(QString, resource); Collection::List origCols = fetchCollections(resource); QVERIFY(!origCols.isEmpty()); CollectionSync *syncer = new CollectionSync(resource, this); syncer->setHierarchicalRemoteIds(hierarchicalRIDs); syncer->setAutoDelete(false); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setStreamingEnabled(true); QTest::qWait(10); QCOMPARE(spy.count(), 0); for (int i = 0; i < origCols.count(); ++i) { Collection::List l; l << origCols[i]; syncer->setRemoteCollections(l); if (i < origCols.count() - 1) { QTest::qWait(10); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } syncer->retrievalDone(); QTRY_COMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1); KJob *job = spy.at(0).at(0).value(); QCOMPARE(job, syncer); QCOMPARE(job->errorText(), QString()); QCOMPARE(job->error(), 0); Collection::List resultCols = fetchCollections(resource); QCOMPARE(resultCols.count(), origCols.count()); delete syncer; } void testIncrementalSync_data() { makeTestData(); } void testIncrementalSync() { QFETCH(bool, hierarchicalRIDs); QFETCH(QString, resource); if (resource == QLatin1String("akonadi_knut_resource_2")) { QSKIP("test requires more than one collection", SkipSingle); } Collection::List origCols = fetchCollections(resource); QVERIFY(!origCols.isEmpty()); CollectionSync *syncer = new CollectionSync(resource, this); syncer->setHierarchicalRemoteIds(hierarchicalRIDs); syncer->setRemoteCollections(origCols, Collection::List()); AKVERIFYEXEC(syncer); Collection::List resultCols = fetchCollections(resource); QCOMPARE(resultCols.count(), origCols.count()); // Find leaf collections that we can delete Collection::List leafCols = resultCols; for (auto iter = leafCols.begin(); iter != leafCols.end();) { bool found = false; Q_FOREACH (const Collection &c, resultCols) { if (c.parentCollection().id() == iter->id()) { iter = leafCols.erase(iter); found = true; break; } } if (!found) { ++iter; } } QVERIFY(!leafCols.isEmpty()); Collection::List delCols; delCols << leafCols.first(); resultCols.removeOne(leafCols.first()); // ### not implemented yet I guess #if 0 Collection colWithOnlyRemoteId; colWithOnlyRemoteId.setRemoteId(resultCols.front().remoteId()); delCols << colWithOnlyRemoteId; resultCols.pop_front(); #endif #if 0 // ### should this work? Collection colWithRandomRemoteId; colWithRandomRemoteId.setRemoteId(KRandom::randomString(100)); delCols << colWithRandomRemoteId; #endif syncer = new CollectionSync(resource, this); syncer->setRemoteCollections(resultCols, delCols); AKVERIFYEXEC(syncer); Collection::List resultCols2 = fetchCollections(resource); QCOMPARE(resultCols2.count(), resultCols.count()); } void testIncrementalStreamingSync_data() { makeTestData(); } void testIncrementalStreamingSync() { QFETCH(bool, hierarchicalRIDs); QFETCH(QString, resource); Collection::List origCols = fetchCollections(resource); QVERIFY(!origCols.isEmpty()); CollectionSync *syncer = new CollectionSync(resource, this); syncer->setHierarchicalRemoteIds(hierarchicalRIDs); syncer->setAutoDelete(false); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setStreamingEnabled(true); QTest::qWait(10); QCOMPARE(spy.count(), 0); for (int i = 0; i < origCols.count(); ++i) { Collection::List l; l << origCols[i]; syncer->setRemoteCollections(l, Collection::List()); if (i < origCols.count() - 1) { QTest::qWait(10); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } syncer->retrievalDone(); QTRY_COMPARE(spy.count(), 1); KJob *job = spy.at(0).at(0).value(); QCOMPARE(job, syncer); QCOMPARE(job->errorText(), QString()); QCOMPARE(job->error(), 0); Collection::List resultCols = fetchCollections(resource); QCOMPARE(resultCols.count(), origCols.count()); delete syncer; } void testEmptyIncrementalSync_data() { makeTestData(); } void testEmptyIncrementalSync() { QFETCH(bool, hierarchicalRIDs); QFETCH(QString, resource); Collection::List origCols = fetchCollections(resource); QVERIFY(!origCols.isEmpty()); CollectionSync *syncer = new CollectionSync(resource, this); syncer->setHierarchicalRemoteIds(hierarchicalRIDs); syncer->setRemoteCollections(Collection::List(), Collection::List()); AKVERIFYEXEC(syncer); Collection::List resultCols = fetchCollections(resource); QCOMPARE(resultCols.count(), origCols.count()); } void testAttributeChanges_data() { QTest::addColumn("keepLocalChanges"); QTest::newRow("keep local changes") << true; QTest::newRow("overwrite local changes") << false; } void testAttributeChanges() { QFETCH(bool, keepLocalChanges); const QString resource(QStringLiteral("akonadi_knut_resource_0")); Collection col = fetchCollections(resource).first(); col.attribute(Akonadi::Collection::AddIfMissing)->setDisplayName(QStringLiteral("foo")); col.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QStringLiteral("foo")); { CollectionModifyJob *job = new CollectionModifyJob(col); AKVERIFYEXEC(job); } col.attribute()->setDisplayName(QStringLiteral("default")); col.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QStringLiteral("default")); CollectionSync *syncer = new CollectionSync(resource, this); if (keepLocalChanges) { syncer->setKeepLocalChanges(QSet() << "ENTITYDISPLAY" << "CONTENTMIMETYPES"); } else { syncer->setKeepLocalChanges(QSet()); } syncer->setRemoteCollections(Collection::List() << col, Collection::List()); AKVERIFYEXEC(syncer); { CollectionFetchJob *job = new CollectionFetchJob(col, Akonadi::CollectionFetchJob::Base); AKVERIFYEXEC(job); Collection resultCol = job->collections().first(); if (keepLocalChanges) { QCOMPARE(resultCol.displayName(), QString::fromLatin1("foo")); QVERIFY(resultCol.contentMimeTypes().contains(QLatin1String("foo"))); } else { QCOMPARE(resultCol.displayName(), QString::fromLatin1("default")); QVERIFY(resultCol.contentMimeTypes().contains(QLatin1String("default"))); } } } // Disabled by default, because they take ~15 minutes to complete #if 0 void benchmarkInitialSync() { const Collection::List collections = prepareBenchmark(); CollectionSync *syncer = prepareBenchmarkSyncer(collections); QBENCHMARK_ONCE { AKVERIFYEXEC(syncer); } cleanupBenchmark(collections); } void benchmarkIncrementalSync() { const Collection::List collections = prepareBenchmark(); // First populate Akonadi with Collections CollectionSync *syncer = prepareBenchmarkSyncer(collections); AKVERIFYEXEC(syncer); // Now create a new syncer to benchmark the incremental sync syncer = prepareBenchmarkSyncer(collections); QBENCHMARK_ONCE { AKVERIFYEXEC(syncer); } cleanupBenchmark(collections); } #endif }; QTEST_AKONADIMAIN(CollectionSyncTest) #include "collectionsynctest.moc" diff --git a/autotests/libs/etmpopulationtest.cpp b/autotests/libs/etmpopulationtest.cpp index a1634e70d..b541086d9 100644 --- a/autotests/libs/etmpopulationtest.cpp +++ b/autotests/libs/etmpopulationtest.cpp @@ -1,351 +1,349 @@ /* Copyright (c) 2013 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include "test_utils.h" - #include "entitytreemodel.h" #include "control.h" #include "entitytreemodel_p.h" #include "monitor_p.h" #include "changerecorder_p.h" #include "qtest_akonadi.h" #include "collectioncreatejob.h" #include "collectiondeletejob.h" #include "itemcreatejob.h" using namespace Akonadi; class ModelSignalSpy : public QObject { Q_OBJECT public: explicit ModelSignalSpy(QAbstractItemModel &model) { connect(&model, &QAbstractItemModel::rowsInserted, this, &ModelSignalSpy::onRowsInserted); connect(&model, &QAbstractItemModel::rowsRemoved, this, &ModelSignalSpy::onRowsRemoved); connect(&model, &QAbstractItemModel::rowsMoved, this, &ModelSignalSpy::onRowsMoved); connect(&model, &QAbstractItemModel::dataChanged, this, &ModelSignalSpy::onDataChanged); connect(&model, &QAbstractItemModel::layoutChanged, this, &ModelSignalSpy::onLayoutChanged); connect(&model, &QAbstractItemModel::modelReset, this, &ModelSignalSpy::onModelReset); } QStringList mSignals; QModelIndex parent; int start; int end; public Q_SLOTS: void onRowsInserted(const QModelIndex &p, int s, int e) { qDebug() << "rowsInserted( parent =" << p << ", start = " << s << ", end = " << e << ", data = " << p.data().toString() << ")"; mSignals << QStringLiteral("rowsInserted"); parent = p; start = s; end = e; } void onRowsRemoved(const QModelIndex &p, int s, int e) { qDebug() << "rowsRemoved( parent = " << p << ", start = " << s << ", end = " << e << ")"; mSignals << QStringLiteral("rowsRemoved"); parent = p; start = s; end = e; } void onRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int) { mSignals << QStringLiteral("rowsMoved"); } void onDataChanged(const QModelIndex &tl, const QModelIndex &br) { qDebug() << "dataChanged( topLeft =" << tl << "(" << tl.data().toString() << "), bottomRight =" << br << "(" << br.data().toString() << ") )"; mSignals << QStringLiteral("dataChanged"); } void onLayoutChanged() { mSignals << QStringLiteral("layoutChanged"); } void onModelReset() { mSignals << QStringLiteral("modelReset"); } }; class InspectableETM: public EntityTreeModel { public: explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr) : EntityTreeModel(monitor, parent) {} EntityTreeModelPrivate *etmPrivate() { return d_ptr; } }; QModelIndex getIndex(const QString &string, EntityTreeModel *model) { QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive); if (list.isEmpty()) { return QModelIndex(); } return list.first(); } Akonadi::Collection createCollection(const QString &name, const Akonadi::Collection &parent, bool enabled = true, const QStringList &mimeTypes = QStringList()) { Akonadi::Collection col; col.setParentCollection(parent); col.setName(name); col.setEnabled(enabled); col.setContentMimeTypes(mimeTypes); CollectionCreateJob *create = new CollectionCreateJob(col); create->exec(); if (create->error()) { qWarning() << create->errorString(); } return create->collection(); } /** * This is a test for the initial population of the ETM. */ class EtmPopulationTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testMonitoringCollectionsPreset(); void testMonitoringCollections(); void testFullPopulation(); void testAddMonitoringCollections(); void testRemoveMonitoringCollections(); void testDisplayFilter(); void testLoadingOfHiddenCollection(); private: Collection res; QString mainCollectionName; Collection monitorCol; Collection col1; Collection col2; Collection col3; Collection col4; }; void EtmPopulationTest::initTestCase() { qRegisterMetaType("Akonadi::Collection::Id"); AkonadiTest::checkTestIsIsolated(); AkonadiTest::setAllResourcesOffline(); - res = Collection(collectionIdFromPath(QStringLiteral("res3"))); + res = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); mainCollectionName = QStringLiteral("main"); monitorCol = createCollection(mainCollectionName, res); QVERIFY(monitorCol.isValid()); col1 = createCollection(QStringLiteral("col1"), monitorCol); QVERIFY(col1.isValid()); col2 = createCollection(QStringLiteral("col2"), monitorCol); QVERIFY(col2.isValid()); col3 = createCollection(QStringLiteral("col3"), monitorCol); QVERIFY(col3.isValid()); col4 = createCollection(QStringLiteral("col4"), col2); QVERIFY(col4.isValid()); } void EtmPopulationTest::testMonitoringCollectionsPreset() { ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(col1, true); changeRecorder->setCollectionMonitored(col2, true); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); QTRY_VERIFY(model->isCollectionTreeFetched()); QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).isValid()); QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); QVERIFY(!getIndex(QStringLiteral("col3"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); } void EtmPopulationTest::testMonitoringCollections() { ChangeRecorder *changeRecorder = new ChangeRecorder(this); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); Akonadi::Collection::List monitored; monitored << col1 << col2; model->setCollectionsMonitored(monitored); QTRY_VERIFY(model->isCollectionTreeFetched()); QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); QVERIFY(!getIndex(QStringLiteral("col3"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); } void EtmPopulationTest::testFullPopulation() { ChangeRecorder *changeRecorder = new ChangeRecorder(this); // changeRecorder->setCollectionMonitored(Akonadi::Collection::root()); changeRecorder->setAllMonitored(true); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); QTRY_VERIFY(model->isCollectionTreeFetched()); QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); QVERIFY(getIndex(mainCollectionName, model).isValid()); QVERIFY(getIndex(QStringLiteral("col3"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); } void EtmPopulationTest::testAddMonitoringCollections() { ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(col1, true); changeRecorder->setCollectionMonitored(col2, true); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); QTRY_VERIFY(model->isCollectionTreeFetched()); //The main collection may be loaded a little later since it is in the fetchAncestors path QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); model->setCollectionMonitored(col3, true); QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col3"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); QVERIFY(getIndex(mainCollectionName, model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col3"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); } void EtmPopulationTest::testRemoveMonitoringCollections() { ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(col1, true); changeRecorder->setCollectionMonitored(col2, true); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); QTRY_VERIFY(model->isCollectionTreeFetched()); //The main collection may be loaded a little later since it is in the fetchAncestors path QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); model->setCollectionMonitored(col2, false); QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); QVERIFY(!getIndex(QStringLiteral("col2"), model).isValid()); QVERIFY(getIndex(mainCollectionName, model).isValid()); QVERIFY(!getIndex(QStringLiteral("col3"), model).isValid()); QVERIFY(!getIndex(QStringLiteral("col4"), model).isValid()); QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(!getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); QTRY_VERIFY(!getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); } void EtmPopulationTest::testDisplayFilter() { Collection col5 = createCollection(QStringLiteral("col5"), monitorCol, false); QVERIFY(col5.isValid()); ChangeRecorder *changeRecorder = new ChangeRecorder(this); InspectableETM *model = new InspectableETM(changeRecorder, this); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); model->setListFilter(Akonadi::CollectionFetchScope::Display); QTRY_VERIFY(model->isCollectionTreeFetched()); QVERIFY(getIndex(mainCollectionName, model).isValid()); QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col3"), model).isValid()); QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); QVERIFY(!getIndex(QStringLiteral("col5"), model).isValid()); Akonadi::CollectionDeleteJob *deleteJob = new Akonadi::CollectionDeleteJob(col5); AKVERIFYEXEC(deleteJob); } /* * Col5 and it's ancestors should be included although the ancestors don't match the mimetype filter. */ void EtmPopulationTest::testLoadingOfHiddenCollection() { Collection col5 = createCollection(QStringLiteral("col5"), monitorCol, false, QStringList() << QStringLiteral("application/test")); QVERIFY(col5.isValid()); ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setMimeTypeMonitored(QStringLiteral("application/test"), true); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); QTRY_VERIFY(model->isCollectionTreeFetched()); QVERIFY(getIndex(QStringLiteral("col5"), model).isValid()); Akonadi::CollectionDeleteJob *deleteJob = new Akonadi::CollectionDeleteJob(col5); AKVERIFYEXEC(deleteJob); } #include "etmpopulationtest.moc" QTEST_AKONADIMAIN(EtmPopulationTest) diff --git a/autotests/libs/favoriteproxytest.cpp b/autotests/libs/favoriteproxytest.cpp index ca81d5f6a..d907bdca3 100644 --- a/autotests/libs/favoriteproxytest.cpp +++ b/autotests/libs/favoriteproxytest.cpp @@ -1,244 +1,243 @@ /* Copyright (c) 2013 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" #include "entitytreemodel.h" #include "control.h" #include "entitytreemodel_p.h" #include "monitor_p.h" #include "changerecorder_p.h" #include "qtest_akonadi.h" #include "collectioncreatejob.h" #include "itemcreatejob.h" #include "favoritecollectionsmodel.h" #include #include #include #include using namespace Akonadi; class InspectableETM: public EntityTreeModel { public: explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr) : EntityTreeModel(monitor, parent) {} EntityTreeModelPrivate *etmPrivate() { return d_ptr; } void reset() { beginResetModel(); endResetModel(); } }; class FavoriteProxyTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testItemAdded(); void testLoadConfig(); void testInsertAfterModelCreation(); private: InspectableETM *createETM(); }; void FavoriteProxyTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Akonadi::Control::start(); AkonadiTest::setAllResourcesOffline(); } QModelIndex getIndex(const QString &string, EntityTreeModel *model) { QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive); if (list.isEmpty()) { return QModelIndex(); } return list.first(); } /** * Since we have no sensible way to figure out if the model is fully populated, * we use the brute force approach. */ bool waitForPopulation(const QModelIndex &idx, EntityTreeModel *model, int count) { for (int i = 0; i < 500; i++) { if (model->rowCount(idx) >= count) { return true; } QTest::qWait(10); } return false; } InspectableETM *FavoriteProxyTest::createETM() { ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(Collection::root()); AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); return model; } /** * Tests that the item is being referenced when added to the favorite proxy, and dereferenced when removed. */ void FavoriteProxyTest::testItemAdded() { - Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); InspectableETM *model = createETM(); KConfigGroup configGroup(KSharedConfig::openConfig(), "favoritecollectionsmodeltest"); FavoriteCollectionsModel *favoriteModel = new FavoriteCollectionsModel(model, configGroup, this); const int numberOfRootCollections = 4; //Wait for initial listing to complete QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); QVERIFY(res3Index.isValid()); const Akonadi::Collection favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value(); QVERIFY(favoriteCollection.isValid()); QVERIFY(!model->etmPrivate()->isMonitored(favoriteCollection.id())); //Ensure the collection is reference counted after being added to the favorite model { favoriteModel->addCollection(favoriteCollection); //the collection is in the favorites model QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); //the collection got referenced QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); //the collection is not yet buffered though QTRY_VERIFY(!model->etmPrivate()->isBuffered(favoriteCollection.id())); } //Survive a reset { QSignalSpy resetSpy(model, &QAbstractItemModel::modelReset); model->reset(); QTRY_COMPARE(resetSpy.count(), 1); //the collection is in the favorites model QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); //the collection got referenced QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); //the collection is not yet buffered though QTRY_VERIFY(!model->etmPrivate()->isBuffered(favoriteCollection.id())); } //Ensure the collection is no longer reference counted after being added to the favorite model, and moved to the buffer { favoriteModel->removeCollection(favoriteCollection); //moved from being reference counted to being buffered QTRY_VERIFY(model->etmPrivate()->isBuffered(favoriteCollection.id())); QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 0); } } void FavoriteProxyTest::testLoadConfig() { InspectableETM *model = createETM(); const int numberOfRootCollections = 4; //Wait for initial listing to complete QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); QVERIFY(res3Index.isValid()); const Akonadi::Collection favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value(); QVERIFY(favoriteCollection.isValid()); KConfigGroup configGroup(KSharedConfig::openConfig(), "favoritecollectionsmodeltest"); configGroup.writeEntry("FavoriteCollectionIds", QList() << favoriteCollection.id()); configGroup.writeEntry("FavoriteCollectionLabels", QStringList() << QStringLiteral("label1")); FavoriteCollectionsModel *favoriteModel = new FavoriteCollectionsModel(model, configGroup, this); { QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); //the collection got referenced QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); } } class Filter: public QSortFilterProxyModel { public: bool filterAcceptsRow(int, const QModelIndex &) const override { return accepts; } bool accepts; }; void FavoriteProxyTest::testInsertAfterModelCreation() { InspectableETM *model = createETM(); Filter filter; filter.accepts = false; filter.setSourceModel(model); const int numberOfRootCollections = 4; //Wait for initial listing to complete QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); QVERIFY(res3Index.isValid()); const Akonadi::Collection favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value(); QVERIFY(favoriteCollection.isValid()); KConfigGroup configGroup(KSharedConfig::openConfig(), "favoritecollectionsmodeltest2"); FavoriteCollectionsModel *favoriteModel = new FavoriteCollectionsModel(&filter, configGroup, this); //Make sure the filter is not letting anything through QTest::qWait(0); QCOMPARE(filter.rowCount(QModelIndex()), 0); //The collection is not in the model yet favoriteModel->addCollection(favoriteCollection); filter.accepts = true; filter.invalidate(); { QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); //the collection got referenced QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); } } #include "favoriteproxytest.moc" QTEST_AKONADIMAIN(FavoriteProxyTest) diff --git a/autotests/libs/gidtest.cpp b/autotests/libs/gidtest.cpp index ddb7c31d1..88959ab1f 100644 --- a/autotests/libs/gidtest.cpp +++ b/autotests/libs/gidtest.cpp @@ -1,205 +1,201 @@ /* Copyright (c) 2013 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gidtest.h" #include "control.h" #include "testattribute.h" #include "agentmanager.h" #include "agentinstance.h" #include "collectionfetchjob.h" #include "itemcreatejob.h" #include "itemdeletejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemmodifyjob.h" #include "qtest_akonadi.h" -#include "test_utils.h" #include "itemserializer_p.h" #include "itemserializerplugin.h" using namespace Akonadi; QTEST_AKONADIMAIN(GidTest) bool TestSerializer::deserialize(Akonadi::Item &item, const QByteArray &label, QIODevice &data, int version) { qDebug() << item.id(); if (label != Akonadi::Item::FullPayload) { return false; } Q_UNUSED(version); item.setPayload(data.readAll()); return true; } void TestSerializer::serialize(const Akonadi::Item &item, const QByteArray &label, QIODevice &data, int &version) { qDebug(); Q_ASSERT(label == Akonadi::Item::FullPayload); Q_UNUSED(label); Q_UNUSED(version); data.write(item.payload()); } QString TestSerializer::extractGid(const Akonadi::Item &item) const { if (item.gid().isEmpty()) { return item.url().url(); } return item.gid(); } void GidTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); ItemSerializer::overridePluginLookup(new TestSerializer); } void GidTest::testSetAndFetch_data() { QTest::addColumn("input"); QTest::addColumn("toFetch"); QTest::addColumn("expected"); Item item1(1); item1.setGid(QStringLiteral("gid1")); Item item2(2); item2.setGid(QStringLiteral("gid2")); Item toFetch; toFetch.setGid(QStringLiteral("gid1")); QTest::newRow("single") << (Item::List() << item1) << toFetch << (Item::List() << item1); QTest::newRow("multi") << (Item::List() << item1 << item2) << toFetch << (Item::List() << item1); { Item item3(3); item2.setGid(QStringLiteral("gid1")); QTest::newRow("multi") << (Item::List() << item1 << item2 << item3) << toFetch << (Item::List() << item1 << item3); } } static void fetchAndSetGid(Item item) { ItemFetchJob *prefetchjob = new ItemFetchJob(item); prefetchjob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(prefetchjob); Item fetchedItem = prefetchjob->items()[0]; //Write the gid to the db fetchedItem.setGid(item.gid()); ItemModifyJob *store = new ItemModifyJob(fetchedItem); store->setUpdateGid(true); AKVERIFYEXEC(store); } void GidTest::testSetAndFetch() { QFETCH(Item::List, input); QFETCH(Item, toFetch); QFETCH(Item::List, expected); Q_FOREACH (const Item &item, input) { fetchAndSetGid(item); } ItemFetchJob *fetch = new ItemFetchJob(toFetch, this); fetch->fetchScope().setFetchGid(true); AKVERIFYEXEC(fetch); Item::List fetched = fetch->items(); QCOMPARE(fetched.count(), expected.size()); Q_FOREACH (const Item &item, expected) { QVERIFY(expected.removeOne(item)); } QVERIFY(expected.isEmpty()); } void GidTest::testCreate() { - CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1/foo/bar"), this); - AKVERIFYEXEC(resolver); - int colId = resolver->collection(); + const int colId = AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bar")); + QVERIFY(colId > -1); Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload(QByteArray("test")); item.setGid(QStringLiteral("createGid")); ItemCreateJob *createJob = new ItemCreateJob(item, Collection(colId), this); AKVERIFYEXEC(createJob); ItemFetchJob *fetch = new ItemFetchJob(item, this); AKVERIFYEXEC(fetch); Item::List fetched = fetch->items(); QCOMPARE(fetched.count(), 1); } void GidTest::testSetWithIgnorePayload() { Item item(5); ItemFetchJob *prefetchjob = new ItemFetchJob(item); prefetchjob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(prefetchjob); Item fetchedItem = prefetchjob->items()[0]; QVERIFY(fetchedItem.gid().isEmpty()); //Write the gid to the db fetchedItem.setGid(QStringLiteral("gid5")); ItemModifyJob *store = new ItemModifyJob(fetchedItem); store->setIgnorePayload(true); store->setUpdateGid(true); AKVERIFYEXEC(store); Item toFetch; toFetch.setGid(QStringLiteral("gid5")); ItemFetchJob *fetch = new ItemFetchJob(toFetch, this); AKVERIFYEXEC(fetch); Item::List fetched = fetch->items(); QCOMPARE(fetched.count(), 1); QCOMPARE(fetched.at(0).id(), Item::Id(5)); } void GidTest::testFetchScope() { - - CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1/foo/bar"), this); - AKVERIFYEXEC(resolver); - int colId = resolver->collection(); + const int colId = AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bar")); + QVERIFY(colId > -1); Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload(QByteArray("test")); item.setGid(QStringLiteral("createGid2")); ItemCreateJob *createJob = new ItemCreateJob(item, Collection(colId), this); AKVERIFYEXEC(createJob); { ItemFetchJob *fetch = new ItemFetchJob(item, this); AKVERIFYEXEC(fetch); Item::List fetched = fetch->items(); QCOMPARE(fetched.count(), 1); QVERIFY(fetched.at(0).gid().isNull()); } { ItemFetchJob *fetch = new ItemFetchJob(item, this); fetch->fetchScope().setFetchGid(true); AKVERIFYEXEC(fetch); Item::List fetched = fetch->items(); QCOMPARE(fetched.count(), 1); QVERIFY(!fetched.at(0).gid().isNull()); } } diff --git a/autotests/libs/invalidatecachejobtest.cpp b/autotests/libs/invalidatecachejobtest.cpp index 9e9296d4f..bac6643c0 100644 --- a/autotests/libs/invalidatecachejobtest.cpp +++ b/autotests/libs/invalidatecachejobtest.cpp @@ -1,89 +1,88 @@ /* Copyright (c) 2019 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "invalidatecachejob_p.h" #include "collectionpathresolver.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "qtest_akonadi.h" -#include "test_utils.h" #include "control.h" using namespace Akonadi; class InvalidateCacheJobTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void shouldClearPayload(); }; void InvalidateCacheJobTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); } void InvalidateCacheJobTest::shouldClearPayload() { // Find collection by name - Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); const int colId = col.id(); QVERIFY(colId > 0); // Find item with remote id "C" auto *listJob = new ItemFetchJob(Collection(colId), this); AKVERIFYEXEC(listJob); const Item::List items = listJob->items(); QVERIFY(!items.isEmpty()); auto it = std::find_if(items.cbegin(), items.cend(), [](const Item &item) { return item.remoteId() == QLatin1Char('C'); }); QVERIFY(it != items.cend()); const Item::Id itemId = it->id(); // Fetch item, from resource, with payload auto *fetchJob = new ItemFetchJob(Item(itemId), this); fetchJob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().payloadData(), "testmailbody2"); // Invalidate cache auto *invCacheJob = new InvalidateCacheJob(Collection(colId), this); AKVERIFYEXEC(invCacheJob); // Fetch item from cache, should have no payload anymore auto *fetchFromCacheJob = new ItemFetchJob(Item(itemId), this); fetchFromCacheJob->fetchScope().fetchFullPayload(); fetchFromCacheJob->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fetchFromCacheJob); QVERIFY(fetchFromCacheJob->items().first().payloadData().isEmpty()); // Fetch item from resource again auto *fetchAgainJob = new ItemFetchJob(Item(itemId), this); fetchAgainJob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(fetchAgainJob); QCOMPARE(fetchAgainJob->items().first().payloadData(), "testmailbody2"); } QTEST_AKONADIMAIN(InvalidateCacheJobTest) #include "invalidatecachejobtest.moc" diff --git a/autotests/libs/itemappendtest.cpp b/autotests/libs/itemappendtest.cpp index 1f33fb14b..3d30db434 100644 --- a/autotests/libs/itemappendtest.cpp +++ b/autotests/libs/itemappendtest.cpp @@ -1,403 +1,403 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemappendtest.h" +#include "qtest_akonadi.h" #include "control.h" #include "testattribute.h" -#include "test_utils.h" #include "agentinstance.h" #include "agentmanager.h" #include "attributefactory.h" #include "collectionfetchjob.h" #include "itemcreatejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemdeletejob.h" #include using namespace Akonadi; QTEST_AKONADIMAIN(ItemAppendTest) void ItemAppendTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AkonadiTest::setAllResourcesOffline(); AttributeFactory::registerAttribute(); } void ItemAppendTest::testItemAppend_data() { QTest::addColumn("remoteId"); QTest::newRow("empty") << QString(); QTest::newRow("non empty") << QStringLiteral("remote-id"); QTest::newRow("whitespace") << QStringLiteral("remote id"); QTest::newRow("quotes") << QStringLiteral("\"remote\" id"); QTest::newRow("brackets") << QStringLiteral("[remote id]"); QTest::newRow("RID length limit") << QStringLiteral("a").repeated(1024); } void ItemAppendTest::testItemAppend() { - const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(testFolder1.isValid()); QFETCH(QString, remoteId); Item ref; // for cleanup Item item(-1); item.setRemoteId(remoteId); item.setMimeType(QStringLiteral("application/octet-stream")); item.setFlag("TestFlag"); item.setSize(3456); ItemCreateJob *job = new ItemCreateJob(item, testFolder1, this); AKVERIFYEXEC(job); ref = job->item(); QCOMPARE(ref.parentCollection(), testFolder1); ItemFetchJob *fjob = new ItemFetchJob(testFolder1, this); fjob->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); QCOMPARE(fjob->items()[0], ref); QCOMPARE(fjob->items()[0].remoteId(), remoteId); QVERIFY(fjob->items()[0].flags().contains("TestFlag")); QCOMPARE(fjob->items()[0].parentCollection(), ref.parentCollection()); qint64 size = 3456; QCOMPARE(fjob->items()[0].size(), size); ItemDeleteJob *djob = new ItemDeleteJob(ref, this); AKVERIFYEXEC(djob); fjob = new ItemFetchJob(testFolder1, this); AKVERIFYEXEC(fjob); QVERIFY(fjob->items().isEmpty()); } void ItemAppendTest::testContent_data() { QTest::addColumn("data"); QTest::newRow("null") << QByteArray(); QTest::newRow("empty") << QByteArray(""); QTest::newRow("nullbyte") << QByteArray("\0", 1); QTest::newRow("nullbyte2") << QByteArray("\0X", 2); QString utf8string = QStringLiteral("äöüß@€µøđ¢©®"); QTest::newRow("utf8") << utf8string.toUtf8(); QTest::newRow("newlines") << QByteArray("\nsome\n\nbreaked\ncontent\n\n"); QByteArray b; QTest::newRow("big") << b.fill('a', 1 << 20); QTest::newRow("bignull") << b.fill('\0', 1 << 20); QTest::newRow("bigcr") << b.fill('\r', 1 << 20); QTest::newRow("biglf") << b.fill('\n', 1 << 20); } void ItemAppendTest::testContent() { - const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(testFolder1.isValid()); QFETCH(QByteArray, data); Item item; item.setMimeType(QStringLiteral("application/octet-stream")); if (!data.isNull()) { item.setPayload(data); } ItemCreateJob *job = new ItemCreateJob(item, testFolder1, this); AKVERIFYEXEC(job); Item ref = job->item(); ItemFetchJob *fjob = new ItemFetchJob(testFolder1, this); fjob->fetchScope().setCacheOnly(true); fjob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); Item item2 = fjob->items().first(); QCOMPARE(item2.hasPayload(), !data.isNull()); if (item2.hasPayload()) { QCOMPARE(item2.payload(), data); } ItemDeleteJob *djob = new ItemDeleteJob(ref, this); AKVERIFYEXEC(djob); } void ItemAppendTest::testNewMimetype() { - const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(col.isValid()); Item item; item.setMimeType(QStringLiteral("application/new-type")); ItemCreateJob *job = new ItemCreateJob(item, col, this); AKVERIFYEXEC(job); item = job->item(); QVERIFY(item.isValid()); ItemFetchJob *fetch = new ItemFetchJob(item, this); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); QCOMPARE(fetch->items().first().mimeType(), item.mimeType()); } void ItemAppendTest::testIllegalAppend() { - const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(testFolder1.isValid()); Item item; item.setMimeType(QStringLiteral("application/octet-stream")); // adding item to non-existing collection ItemCreateJob *job = new ItemCreateJob(item, Collection(INT_MAX), this); QVERIFY(!job->exec()); // adding item into a collection which can't handle items of this type - const Collection col(collectionIdFromPath(QStringLiteral("res1/foo/bla"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bla"))); QVERIFY(col.isValid()); job = new ItemCreateJob(item, col, this); QEXPECT_FAIL("", "Test not yet implemented in the server.", Continue); QVERIFY(!job->exec()); } void ItemAppendTest::testMultipartAppend() { - const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(testFolder1.isValid()); Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload("body data"); item.attribute(Item::AddIfMissing)->data = "extra data"; item.setFlag("TestFlag"); ItemCreateJob *job = new ItemCreateJob(item, testFolder1, this); AKVERIFYEXEC(job); Item ref = job->item(); ItemFetchJob *fjob = new ItemFetchJob(ref, this); fjob->fetchScope().fetchFullPayload(); fjob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items().first(); QCOMPARE(item.payload(), QByteArray("body data")); QVERIFY(item.hasAttribute()); QCOMPARE(item.attribute()->data, QByteArray("extra data")); QVERIFY(item.flags().contains("TestFlag")); ItemDeleteJob *djob = new ItemDeleteJob(ref, this); AKVERIFYEXEC(djob); } void ItemAppendTest::testInvalidMultipartAppend() { Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload("body data"); item.attribute(Item::AddIfMissing)->data = "extra data"; item.setFlag("TestFlag"); ItemCreateJob *job = new ItemCreateJob(item, Collection(-1), this); QVERIFY(!job->exec()); Item item2; item2.setMimeType(QStringLiteral("application/octet-stream")); item2.setPayload("more body data"); item2.attribute(Item::AddIfMissing)->data = "even more extra data"; item2.setFlag("TestFlag"); ItemCreateJob *job2 = new ItemCreateJob(item2, Collection(-1), this); QVERIFY(!job2->exec()); } void ItemAppendTest::testItemSize_data() { QTest::addColumn("item"); QTest::addColumn("size"); Item i(QStringLiteral("application/octet-stream")); i.setPayload(QByteArray("ABCD")); QTest::newRow("auto size") << i << 4ll; i.setSize(3); QTest::newRow("too small") << i << 4ll; i.setSize(10); QTest::newRow("too large") << i << 10ll; } void ItemAppendTest::testItemSize() { QFETCH(Akonadi::Item, item); QFETCH(qint64, size); - const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(col.isValid()); ItemCreateJob *create = new ItemCreateJob(item, col, this); AKVERIFYEXEC(create); Item newItem = create->item(); ItemFetchJob *fetch = new ItemFetchJob(newItem, this); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); QCOMPARE(fetch->items().first().size(), size); } void ItemAppendTest::testItemMerge_data() { QTest::addColumn("item1"); QTest::addColumn("item2"); QTest::addColumn("mergedItem"); QTest::addColumn("silent"); { Item i1(QStringLiteral("application/octet-stream")); i1.setPayload(QByteArray("ABCD")); i1.setSize(4); i1.setRemoteId(QStringLiteral("XYZ")); i1.setGid(QStringLiteral("XYZ")); i1.setFlag("TestFlag1"); i1.setRemoteRevision(QStringLiteral("5")); Item i2(QStringLiteral("application/octet-stream")); i2.setPayload(QByteArray("DEFGH")); i2.setSize(5); i2.setRemoteId(QStringLiteral("XYZ")); i2.setGid(QStringLiteral("XYZ")); i2.setFlag("TestFlag2"); i2.setRemoteRevision(QStringLiteral("6")); Item mergedItem(i2); mergedItem.setFlag("TestFlag1"); QTest::newRow("merge") << i1 << i2 << mergedItem << false; QTest::newRow("merge (silent)") << i1 << i2 << mergedItem << true; } { Item i1(QStringLiteral("application/octet-stream")); i1.setPayload(QByteArray("ABCD")); i1.setSize(4); i1.setRemoteId(QStringLiteral("RID2")); i1.setGid(QStringLiteral("GID2")); i1.setFlag("TestFlag1"); i1.setRemoteRevision(QStringLiteral("5")); Item i2(QStringLiteral("application/octet-stream")); i2.setRemoteId(QStringLiteral("RID2")); i2.setGid(QStringLiteral("GID2")); i2.setFlags(Item::Flags() << "TestFlag2"); i2.setRemoteRevision(QStringLiteral("6")); Item mergedItem(i1); mergedItem.setFlags(i2.flags()); mergedItem.setRemoteRevision(i2.remoteRevision()); QTest::newRow("overwrite flags, and don't remove existing payload") << i1 << i2 << mergedItem << false; QTest::newRow("overwrite flags, and don't remove existing payload (silent)") << i1 << i2 << mergedItem << true; } } void ItemAppendTest::testItemMerge() { QFETCH(Akonadi::Item, item1); QFETCH(Akonadi::Item, item2); QFETCH(Akonadi::Item, mergedItem); QFETCH(bool, silent); - const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(col.isValid()); ItemCreateJob *create = new ItemCreateJob(item1, col, this); AKVERIFYEXEC(create); const Item createdItem = create->item(); ItemCreateJob *merge = new ItemCreateJob(item2, col, this); ItemCreateJob::MergeOptions options = ItemCreateJob::GID | ItemCreateJob::RID; if (silent) { options |= ItemCreateJob::Silent; } merge->setMerge(options); AKVERIFYEXEC(merge); QCOMPARE(merge->item().id(), createdItem.id()); if (!silent) { QCOMPARE(merge->item().gid(), mergedItem.gid()); QCOMPARE(merge->item().remoteId(), mergedItem.remoteId()); QCOMPARE(merge->item().remoteRevision(), mergedItem.remoteRevision()); QCOMPARE(merge->item().payloadData(), mergedItem.payloadData()); QCOMPARE(merge->item().size(), mergedItem.size()); qDebug() << merge->item().flags() << mergedItem.flags(); QCOMPARE(merge->item().flags(), mergedItem.flags()); } if (merge->item().id() != createdItem.id()) { ItemDeleteJob *del = new ItemDeleteJob(merge->item(), this); AKVERIFYEXEC(del); } ItemDeleteJob *del = new ItemDeleteJob(createdItem, this); AKVERIFYEXEC(del); } void ItemAppendTest::testForeignPayload() { - const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); QVERIFY(col.isValid()); const QString filePath = QString::fromUtf8(qgetenv("TMPDIR")) + QStringLiteral("/foreignPayloadFile.mbox"); QFile file(filePath); QVERIFY(file.open(QIODevice::WriteOnly)); file.write("123456789"); file.close(); Item item(QStringLiteral("application/octet-stream")); item.setPayloadPath(filePath); item.setRemoteId(QStringLiteral("RID3")); item.setSize(9); ItemCreateJob *create = new ItemCreateJob(item, col, this); AKVERIFYEXEC(create); auto ref = create->item(); ItemFetchJob *fetch = new ItemFetchJob(ref, this); fetch->fetchScope().fetchFullPayload(true); AKVERIFYEXEC(fetch); const auto items = fetch->items(); QCOMPARE(items.size(), 1); item = items[0]; QVERIFY(item.hasPayload()); QCOMPARE(item.payload(), QByteArray("123456789")); ItemDeleteJob *del = new ItemDeleteJob(item, this); AKVERIFYEXEC(del); // Make sure Akonadi does not delete a foreign payload QVERIFY(file.exists()); QVERIFY(file.remove()); } diff --git a/autotests/libs/itembenchmark.cpp b/autotests/libs/itembenchmark.cpp index e45ace85e..17f73cc4d 100644 --- a/autotests/libs/itembenchmark.cpp +++ b/autotests/libs/itembenchmark.cpp @@ -1,199 +1,198 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "agentinstance.h" #include "agentmanager.h" #include "item.h" #include "itemcreatejob.h" #include "itemdeletejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemmodifyjob.h" #include "qtest_akonadi.h" -#include "test_utils.h" #include using namespace Akonadi; class ItemBenchmark : public QObject { Q_OBJECT public Q_SLOTS: void createResult(KJob *job) { Q_ASSERT(job->error() == KJob::NoError); Item createdItem = static_cast(job)->item(); mCreatedItems[createdItem.size()].append(createdItem); } void fetchResult(KJob *job) { Q_ASSERT(job->error() == KJob::NoError); } void modifyResult(KJob *job) { Q_ASSERT(job->error() == KJob::NoError); } private: QMap mCreatedItems; private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); AkonadiTest::setAllResourcesOffline(); } void data() { QTest::addColumn("count"); QTest::addColumn("size"); QList counts = QList() << 1 << 10 << 100 << 1000; // << 10000; QList sizes = QList() << 0 << 256 << 1024 << 8192 << 32768 << 65536; foreach (int count, counts) foreach (int size, sizes) QTest::newRow(QString::fromLatin1("%1-%2").arg(count).arg(size).toLatin1().constData()) << count << size; } void itemBenchmarkCreate_data() { data(); } void itemBenchmarkCreate() /// Tests performance of creating items in the cache { QFETCH(int, count); QFETCH(int, size); - const Collection parent(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection parent(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(parent.isValid()); Item item(QStringLiteral("application/octet-stream")); item.setPayload(QByteArray(size, 'X')); item.setSize(size); Job *lastJob = 0; QBENCHMARK { for (int i = 0; i < count; ++i) { lastJob = new ItemCreateJob(item, parent, this); connect(lastJob, SIGNAL(result(KJob*)), SLOT(createResult(KJob*))); } AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*))); } } void itemBenchmarkFetch_data() { data(); } void itemBenchmarkFetch() /// Tests performance of fetching cached items { QFETCH(int, count); QFETCH(int, size); // With only one iteration itemBenchmarkCreate() should have created count // items, otherwise iterations * count, however, at least count items should // be there. QVERIFY(mCreatedItems.value(size).count() >= count); QBENCHMARK { Item::List items; for (int i = 0; i < count; ++i) { items << mCreatedItems[size].at(i); } ItemFetchJob *fetchJob = new ItemFetchJob(items, this); fetchJob->fetchScope().fetchFullPayload(); fetchJob->fetchScope().setCacheOnly(true); connect(fetchJob, SIGNAL(result(KJob*)), SLOT(fetchResult(KJob*))); AkonadiTest::akWaitForSignal(fetchJob, SIGNAL(result(KJob*))); } } void itemBenchmarkModifyPayload_data() { data(); } void itemBenchmarkModifyPayload() /// Tests performance of modifying payload of cached items { QFETCH(int, count); QFETCH(int, size); // With only one iteration itemBenchmarkCreate() should have created count // items, otherwise iterations * count, however, at least count items should // be there. QVERIFY(mCreatedItems.value(size).count() >= count); Job *lastJob = 0; const int newSize = qMax(size, 1); QBENCHMARK { for (int i = 0; i < count; ++i) { Item item = mCreatedItems.value(size).at(i); item.setPayload(QByteArray(newSize, 'Y')); ItemModifyJob *job = new ItemModifyJob(item, this); job->disableRevisionCheck(); lastJob = job; connect(lastJob, SIGNAL(result(KJob*)), SLOT(modifyResult(KJob*))); } AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*))); } } void itemBenchmarkDelete_data() { data(); } void itemBenchmarkDelete() /// Tests performance of removing items from the cache { QFETCH(int, count); QFETCH(int, size); Job *lastJob = 0; int emptyItemArrayIterations = 0; QBENCHMARK { if (mCreatedItems[size].isEmpty()) { ++emptyItemArrayIterations; } Item::List items; for (int i = 0; i < count && !mCreatedItems[size].isEmpty(); ++i) { items << mCreatedItems[size].takeFirst(); } lastJob = new ItemDeleteJob(items, this); AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*))); } if (emptyItemArrayIterations) { qDebug() << "Delete Benchmark performed" << emptyItemArrayIterations << "times on an empty list."; } } }; QTEST_AKONADIMAIN(ItemBenchmark) #include "itembenchmark.moc" diff --git a/autotests/libs/itemcopytest.cpp b/autotests/libs/itemcopytest.cpp index 3999e6522..ba9c74c96 100644 --- a/autotests/libs/itemcopytest.cpp +++ b/autotests/libs/itemcopytest.cpp @@ -1,136 +1,135 @@ /* Copyright (c) 2008 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "agentinstance.h" #include "agentmanager.h" #include "collection.h" #include "collectionstatistics.h" #include "control.h" #include "itemcopyjob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemcreatejob.h" -#include "test_utils.h" #include "qtest_akonadi.h" #include #include using namespace Akonadi; class ItemCopyTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); // switch target resources offline to reduce interference from them foreach (Akonadi::AgentInstance agent, Akonadi::AgentManager::self()->instances()) { //krazy:exclude=foreach if (agent.identifier() == QLatin1String("akonadi_knut_resource_2")) { agent.setIsOnline(false); } } } void testCopy() { - const Collection target(collectionIdFromPath(QStringLiteral("res3"))); + const Collection target(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); QVERIFY(target.isValid()); ItemCopyJob *copy = new ItemCopyJob(Item(1), target); AKVERIFYEXEC(copy); Item source(1); ItemFetchJob *sourceFetch = new ItemFetchJob(source); AKVERIFYEXEC(sourceFetch); source = sourceFetch->items().first(); ItemFetchJob *fetch = new ItemFetchJob(target); fetch->fetchScope().fetchFullPayload(); fetch->fetchScope().fetchAllAttributes(); fetch->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); Item item = fetch->items().first(); QVERIFY(item.hasPayload()); QVERIFY(source.size() > 0); QVERIFY(item.size() > 0); QCOMPARE(item.size(), source.size()); QCOMPARE(item.attributes().count(), 1); QVERIFY(item.remoteId().isEmpty()); QEXPECT_FAIL("", "statistics are not properly updated after copy", Abort); QCOMPARE(target.statistics().count(), 1ll); } void testIlleagalCopy() { // empty item list ItemCopyJob *copy = new ItemCopyJob(Item::List(), Collection::root()); QVERIFY(!copy->exec()); // non-existing target copy = new ItemCopyJob(Item(1), Collection(INT_MAX)); QVERIFY(!copy->exec()); // non-existing source copy = new ItemCopyJob(Item(INT_MAX), Collection::root()); QVERIFY(!copy->exec()); } void testCopyForeign() { QTemporaryFile file; QVERIFY(file.open()); file.write("123456789"); file.close(); - const Collection source(collectionIdFromPath(QStringLiteral("res2"))); + const Collection source(AkonadiTest::collectionIdFromPath(QStringLiteral("res2"))); Item item(QStringLiteral("application/octet-stream")); item.setPayloadPath(file.fileName()); auto create = new ItemCreateJob(item, source, this); AKVERIFYEXEC(create); item = create->item(); - const Collection target(collectionIdFromPath(QStringLiteral("res2/space folder"))); + const Collection target(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); auto copy = new ItemCopyJob(item, target, this); AKVERIFYEXEC(copy); auto fetch = new ItemFetchJob(target, this); fetch->fetchScope().fetchFullPayload(true); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().size(), 1); auto copiedItem = fetch->items().at(0); // Copied payload should be completely stored inside Akonadi QVERIFY(copiedItem.payloadPath().isEmpty()); QVERIFY(copiedItem.hasPayload()); QCOMPARE(copiedItem.payload(), item.payload()); } }; QTEST_AKONADIMAIN(ItemCopyTest) #include "itemcopytest.moc" diff --git a/autotests/libs/itemdeletetest.cpp b/autotests/libs/itemdeletetest.cpp index b8e164a63..d861be863 100644 --- a/autotests/libs/itemdeletetest.cpp +++ b/autotests/libs/itemdeletetest.cpp @@ -1,237 +1,236 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "qtest_akonadi.h" #include "collection.h" #include "collectionpathresolver.h" #include "control.h" #include "itemdeletejob.h" #include "itemfetchjob.h" #include "transactionjobs.h" #include "tagcreatejob.h" #include "itemmodifyjob.h" #include "resourceselectjob_p.h" #include "monitor.h" -#include "test_utils.h" #include #include using namespace Akonadi; class ItemDeleteTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); } void testIllegalDelete() { ItemDeleteJob *djob = new ItemDeleteJob(Item(INT_MAX), this); QVERIFY(!djob->exec()); // make sure a failed delete doesn't leave a transaction open (the kpilot bug) TransactionRollbackJob *tjob = new TransactionRollbackJob(this); QVERIFY(!tjob->exec()); } void testDelete() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy spy(monitor.get(), &Monitor::itemsRemoved); ItemFetchJob *fjob = new ItemFetchJob(Item(1), this); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); ItemDeleteJob *djob = new ItemDeleteJob(Item(1), this); AKVERIFYEXEC(djob); fjob = new ItemFetchJob(Item(1), this); QVERIFY(!fjob->exec()); QTRY_COMPARE(spy.count(), 1); auto items = spy.at(0).at(0).value(); QCOMPARE(items.count(), 1); QCOMPARE(items.at(0).id(), 1); QVERIFY(items.at(0).parentCollection().isValid()); } void testDeleteFromUnselectedCollection() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy spy(monitor.get(), &Monitor::itemsRemoved); const QString path = QLatin1String("res1") + CollectionPathResolver::pathDelimiter() + QLatin1String("foo"); CollectionPathResolver *rjob = new CollectionPathResolver(path, this); AKVERIFYEXEC(rjob); ItemFetchJob *fjob = new ItemFetchJob(Collection(rjob->collection()), this); AKVERIFYEXEC(fjob); const Item::List items = fjob->items(); QVERIFY(!items.isEmpty()); fjob = new ItemFetchJob(items[ 0 ], this); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); ItemDeleteJob *djob = new ItemDeleteJob(items[ 0 ], this); AKVERIFYEXEC(djob); fjob = new ItemFetchJob(items[ 0 ], this); QVERIFY(!fjob->exec()); QTRY_COMPARE(spy.count(), 1); auto ntfItems = spy.at(0).at(0).value(); QCOMPARE(ntfItems.count(), 1); QCOMPARE(ntfItems.at(0).id(), items[0].id()); QVERIFY(ntfItems.at(0).parentCollection().isValid()); } void testRidDelete() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy spy(monitor.get(), &Monitor::itemsRemoved); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); } - const Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item i; i.setRemoteId(QStringLiteral("C")); ItemFetchJob *fjob = new ItemFetchJob(i, this); fjob->setCollection(col); AKVERIFYEXEC(fjob); auto items = fjob->items(); QCOMPARE(items.count(), 1); ItemDeleteJob *djob = new ItemDeleteJob(i, this); AKVERIFYEXEC(djob); QTRY_COMPARE(spy.count(), 1); auto ntfItems = spy.at(0).at(0).value(); QCOMPARE(ntfItems.count(), 1); QCOMPARE(ntfItems.at(0).id(), items[0].id()); QVERIFY(ntfItems.at(0).parentCollection().isValid()); fjob = new ItemFetchJob(i, this); fjob->setCollection(col); QVERIFY(!fjob->exec()); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); AKVERIFYEXEC(select); } } void testTagDelete() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy spy(monitor.get(), &Monitor::itemsRemoved); // Create tag Tag tag; tag.setName(QStringLiteral("Tag1")); tag.setGid("Tag1"); TagCreateJob *tjob = new TagCreateJob(tag, this); AKVERIFYEXEC(tjob); tag = tjob->tag(); - const Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item i; i.setRemoteId(QStringLiteral("D")); ItemFetchJob *fjob = new ItemFetchJob(i, this); fjob->setCollection(col); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); i = fjob->items().first(); i.setTag(tag); ItemModifyJob *mjob = new ItemModifyJob(i, this); AKVERIFYEXEC(mjob); // Delete the tagged item ItemDeleteJob *djob = new ItemDeleteJob(tag, this); AKVERIFYEXEC(djob); QTRY_COMPARE(spy.count(), 1); auto ntfItems = spy.at(0).at(0).value(); QCOMPARE(ntfItems.count(), 1); QCOMPARE(ntfItems.at(0).id(), i.id()); QVERIFY(ntfItems.at(0).parentCollection().isValid()); // Try to fetch the item again, there should be none fjob = new ItemFetchJob(i, this); QVERIFY(!fjob->exec()); } void testCollectionDelete() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy spy(monitor.get(), &Monitor::itemsRemoved); - const Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); ItemFetchJob *fjob = new ItemFetchJob(col, this); AKVERIFYEXEC(fjob); auto items = fjob->items(); QVERIFY(items.count() > 0); // delete from non-empty collection ItemDeleteJob *djob = new ItemDeleteJob(col, this); AKVERIFYEXEC(djob); QTRY_COMPARE(spy.count(), 1); auto ntfItems = spy.at(0).at(0).value(); QCOMPARE(ntfItems.count(), items.count()); if (ntfItems.count() > 0) { QVERIFY(ntfItems.at(0).parentCollection().isValid()); } fjob = new ItemFetchJob(col, this); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 0); // delete from empty collection djob = new ItemDeleteJob(col, this); QVERIFY(!djob->exec()); // error: no items found fjob = new ItemFetchJob(col, this); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 0); } }; QTEST_AKONADIMAIN(ItemDeleteTest) #include "itemdeletetest.moc" diff --git a/autotests/libs/itemmovetest.cpp b/autotests/libs/itemmovetest.cpp index c10ff5da5..b6b4e8756 100644 --- a/autotests/libs/itemmovetest.cpp +++ b/autotests/libs/itemmovetest.cpp @@ -1,188 +1,186 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" - #include "collection.h" #include "control.h" #include "itemfetchjob.h" #include "itemcreatejob.h" #include "itemmovejob.h" #include "itemfetchscope.h" #include "collectionfetchscope.h" #include "monitor.h" #include "session.h" #include "qtest_akonadi.h" #include "resourceselectjob_p.h" #include using namespace Akonadi; class ItemMoveTest: public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); } // TODO: test inter and intra resource moves void testMove_data() { QTest::addColumn("items"); QTest::addColumn("destination"); QTest::addColumn("source"); - Collection destination(collectionIdFromPath(QStringLiteral("res1/foo/bar"))); + Collection destination(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bar"))); QVERIFY(destination.isValid()); QTest::newRow("intra-res single uid") << (Item::List() << Item(5)) << destination << Collection(); - destination = Collection(collectionIdFromPath(QStringLiteral("res3"))); + destination = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); QVERIFY(destination.isValid()); QTest::newRow("inter-res single uid") << (Item::List() << Item(1)) << destination << Collection(); QTest::newRow("inter-res two uid") << (Item::List() << Item(2) << Item(3)) << destination << Collection(); Item r1; r1.setRemoteId(QStringLiteral("D")); Collection ridDest; ridDest.setRemoteId(QStringLiteral("3")); Collection ridSource; ridSource.setRemoteId(QStringLiteral("10")); QTest::newRow("intra-res single rid") << (Item::List() << r1) << ridDest << ridSource; } void testMove() { QFETCH(Item::List, items); QFETCH(Collection, destination); QFETCH(Collection, source); Session monitorSession; Monitor monitor(&monitorSession); monitor.setObjectName(QStringLiteral("itemmovetest")); monitor.setCollectionMonitored(Collection::root()); monitor.fetchCollection(true); monitor.itemFetchScope().setAncestorRetrieval(ItemFetchScope::Parent); monitor.itemFetchScope().setFetchRemoteIdentification(true); QSignalSpy moveSpy(&monitor, &Monitor::itemsMoved); AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady); ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); // for rid based moves ItemFetchJob *prefetchjob = new ItemFetchJob(destination, this); AKVERIFYEXEC(prefetchjob); int baseline = prefetchjob->items().size(); ItemMoveJob *move = new ItemMoveJob(items, source, destination, this); AKVERIFYEXEC(move); ItemFetchJob *fetch = new ItemFetchJob(destination, this); fetch->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent); fetch->fetchScope().fetchFullPayload(); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), items.count() + baseline); foreach (const Item &movedItem, fetch->items()) { QVERIFY(movedItem.hasPayload()); QVERIFY(!movedItem.payload().isEmpty()); if (destination.id() >= 0) { QCOMPARE(movedItem.parentCollection().id(), destination.id()); } else { QCOMPARE(movedItem.parentCollection().remoteId(), destination.remoteId()); } } QTRY_COMPARE(moveSpy.count(), 1); const Akonadi::Item::List &ntfItems = moveSpy.takeFirst().at(0).value(); QCOMPARE(ntfItems.size(), items.size()); Q_FOREACH (const Item &ntfItem, ntfItems) { if (destination.id() >= 0) { QCOMPARE(ntfItem.parentCollection().id(), destination.id()); } else { QCOMPARE(ntfItem.parentCollection().remoteId(), destination.remoteId()); } } } void testIllegalMove() { - Collection col(collectionIdFromPath(QStringLiteral("res2"))); + Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2"))); QVERIFY(col.isValid()); ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(prefetchjob); QCOMPARE(prefetchjob->items().count(), 1); Item item = prefetchjob->items()[0]; // move into invalid collection ItemMoveJob *store = new ItemMoveJob(item, Collection(INT_MAX), this); QVERIFY(!store->exec()); - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy itemMovedSpy(monitor.get(), &Monitor::itemsMoved); // move item into folder that doesn't support its mimetype store = new ItemMoveJob(item, col, this); QEXPECT_FAIL("", "Check not yet implemented by the server.", Continue); QVERIFY(!store->exec()); // Wait for the notification so that it does not disturb the next test QTRY_COMPARE(itemMovedSpy.count(), 1); } void testMoveNotifications() { - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy itemMovedSpy(monitor.get(), &Monitor::itemsMoved); QSignalSpy itemAddedSpy(monitor.get(), &Monitor::itemAdded); - Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); Item item(QStringLiteral("application/octet-stream")); item.setFlags({ "\\SEEN", "$ENCRYPTED" }); item.setPayload(QByteArray("This is a test payload")); item.setSize(34); item.setParentCollection(col); auto create = new ItemCreateJob(item, col, this); AKVERIFYEXEC(create); item = create->item(); QTRY_COMPARE(itemAddedSpy.size(), 1); auto ntfItem = itemAddedSpy.at(0).at(0).value(); QCOMPARE(ntfItem.id(), item.id()); QCOMPARE(ntfItem.flags(), item.flags()); - Collection dest(collectionIdFromPath(QStringLiteral("res1/foo/bar"))); + Collection dest(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bar"))); auto move = new ItemMoveJob(item, dest, this); AKVERIFYEXEC(move); QTRY_COMPARE(itemMovedSpy.size(), 1); const auto ntfItems = itemMovedSpy.at(0).at(0).value(); QCOMPARE(ntfItems.size(), 1); ntfItem = ntfItems.at(0); QCOMPARE(ntfItem.id(), item.id()); QCOMPARE(ntfItem.flags(), item.flags()); } }; QTEST_AKONADIMAIN(ItemMoveTest) #include "itemmovetest.moc" diff --git a/autotests/libs/itemsearchjobtest.cpp b/autotests/libs/itemsearchjobtest.cpp index 2c8723cfa..3eb5fb6a4 100644 --- a/autotests/libs/itemsearchjobtest.cpp +++ b/autotests/libs/itemsearchjobtest.cpp @@ -1,103 +1,103 @@ /* Copyright (c) 2014 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" +#include "qtest_akonadi.h" #include "collection.h" #include "item.h" #include "agentmanager.h" #include "agentinstance.h" #include "itemsearchjob.h" #include "searchquery.h" Q_DECLARE_METATYPE(QSet) Q_DECLARE_METATYPE(Akonadi::SearchQuery) using namespace Akonadi; class ItemSearchJobTest : public QObject { Q_OBJECT private: Akonadi::SearchQuery createQuery(const QString &key, const QSet< qint64 > &resultSet) { Akonadi::SearchQuery query; foreach (qint64 id, resultSet) { query.addTerm(Akonadi::SearchTerm(key, id)); } return query; } private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testItemSearch_data() { QTest::addColumn("remoteSearchEnabled"); QTest::addColumn("query"); QTest::addColumn >("resultSet"); { QSet resultSet; resultSet << 1 << 2 << 3; QTest::newRow("plugin search") << false << createQuery(QStringLiteral("plugin"), resultSet) << resultSet; } { QSet resultSet; resultSet << 1 << 2 << 3; QTest::newRow("resource search") << true << createQuery(QStringLiteral("resource"), resultSet) << resultSet; } { QSet resultSet; resultSet << 1 << 2 << 3 << 4; Akonadi::SearchQuery query; query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 1)); query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 2)); query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 3)); query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 4)); QTest::newRow("mixed search: results are merged") << true << query << resultSet; } } void testItemSearch() { QFETCH(bool, remoteSearchEnabled); QFETCH(SearchQuery, query); QFETCH(QSet, resultSet); ItemSearchJob *itemSearchJob = new ItemSearchJob(query, this); itemSearchJob->setRemoteSearchEnabled(remoteSearchEnabled); itemSearchJob->setSearchCollections(Collection::List() << Collection::root()); itemSearchJob->setRecursive(true); AKVERIFYEXEC(itemSearchJob); QSet actualResultSet; foreach (const Item &item, itemSearchJob->items()) { actualResultSet << item.id(); } qDebug() << actualResultSet << resultSet; QCOMPARE(actualResultSet, resultSet); } }; QTEST_AKONADIMAIN(ItemSearchJobTest) #include "itemsearchjobtest.moc" diff --git a/autotests/libs/itemstoretest.cpp b/autotests/libs/itemstoretest.cpp index 0b22b1c45..5c95a2a9a 100644 --- a/autotests/libs/itemstoretest.cpp +++ b/autotests/libs/itemstoretest.cpp @@ -1,510 +1,509 @@ /* Copyright (c) 2006 Volker Krause Copyright (c) 2007 Robert Zwerus This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemstoretest.h" #include "control.h" #include "testattribute.h" #include "agentmanager.h" #include "agentinstance.h" #include "attributefactory.h" #include "collectionfetchjob.h" #include "itemcreatejob.h" #include "itemdeletejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemmodifyjob.h" #include "itemmodifyjob_p.h" #include "resourceselectjob_p.h" #include "qtest_akonadi.h" -#include "test_utils.h" using namespace Akonadi; QTEST_AKONADIMAIN(ItemStoreTest) static Collection res1_foo; static Collection res2; static Collection res3; void ItemStoreTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AttributeFactory::registerAttribute(); // get the collections we run the tests on - res1_foo = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + res1_foo = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(res1_foo.isValid()); - res2 = Collection(collectionIdFromPath(QStringLiteral("res2"))); + res2 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2"))); QVERIFY(res2.isValid()); - res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); QVERIFY(res3.isValid()); AkonadiTest::setAllResourcesOffline(); } void ItemStoreTest::testFlagChange() { ItemFetchJob *fjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); Item item = fjob->items()[0]; // add a flag Item::Flags origFlags = item.flags(); Item::Flags expectedFlags = origFlags; expectedFlags.insert("added_test_flag_1"); item.setFlag("added_test_flag_1"); ItemModifyJob *sjob = new ItemModifyJob(item, this); AKVERIFYEXEC(sjob); fjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items()[0]; QCOMPARE(item.flags().count(), expectedFlags.count()); Item::Flags diff = expectedFlags - item.flags(); QVERIFY(diff.isEmpty()); // set flags expectedFlags.insert("added_test_flag_2"); item.setFlags(expectedFlags); sjob = new ItemModifyJob(item, this); AKVERIFYEXEC(sjob); fjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items()[0]; QCOMPARE(item.flags().count(), expectedFlags.count()); diff = expectedFlags - item.flags(); QVERIFY(diff.isEmpty()); // remove a flag item.clearFlag("added_test_flag_1"); item.clearFlag("added_test_flag_2"); sjob = new ItemModifyJob(item, this); AKVERIFYEXEC(sjob); fjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items()[0]; QCOMPARE(item.flags().count(), origFlags.count()); diff = origFlags - item.flags(); QVERIFY(diff.isEmpty()); } void ItemStoreTest::testDataChange_data() { QTest::addColumn("data"); QTest::newRow("simple") << QByteArray("testbody"); QTest::newRow("null") << QByteArray(); QTest::newRow("empty") << QByteArray(""); QTest::newRow("nullbyte") << QByteArray("\0", 1); QTest::newRow("nullbyte2") << QByteArray("\0X", 2); QTest::newRow("linebreaks") << QByteArray("line1\nline2\n\rline3\rline4\r\n"); QTest::newRow("linebreaks2") << QByteArray("line1\r\nline2\r\n\r\n"); QTest::newRow("linebreaks3") << QByteArray("line1\nline2"); QByteArray b; QTest::newRow("big") << b.fill('a', 1 << 20); QTest::newRow("bignull") << b.fill('\0', 1 << 20); QTest::newRow("bigcr") << b.fill('\r', 1 << 20); QTest::newRow("biglf") << b.fill('\n', 1 << 20); } void ItemStoreTest::testDataChange() { QFETCH(QByteArray, data); Item item; ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(prefetchjob); item = prefetchjob->items()[0]; item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload(data); QCOMPARE(item.payload(), data); // modify data ItemModifyJob *sjob = new ItemModifyJob(item); AKVERIFYEXEC(sjob); ItemFetchJob *fjob = new ItemFetchJob(Item(1)); fjob->fetchScope().fetchFullPayload(); fjob->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items()[0]; QVERIFY(item.hasPayload()); QCOMPARE(item.payload(), data); QEXPECT_FAIL("null", "STORE will not update item size on 0 sizes", Continue); QEXPECT_FAIL("empty", "STORE will not update item size on 0 sizes", Continue); QCOMPARE(item.size(), static_cast(data.size())); } void ItemStoreTest::testRemoteId_data() { QTest::addColumn("rid"); QTest::addColumn("exprid"); QTest::newRow("set") << QStringLiteral("A") << QStringLiteral("A"); QTest::newRow("no-change") << QString() << QStringLiteral("A"); QTest::newRow("clear") << QStringLiteral("") << QStringLiteral(""); QTest::newRow("reset") << QStringLiteral("A") << QStringLiteral("A"); QTest::newRow("utf8") << QStringLiteral("ä ö ü @") << QStringLiteral("ä ö ü @"); } void ItemStoreTest::testRemoteId() { QFETCH(QString, rid); QFETCH(QString, exprid); // pretend to be a resource, we cannot change remote identifiers otherwise ResourceSelectJob *rsel = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0"), this); AKVERIFYEXEC(rsel); ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(prefetchjob); Item item = prefetchjob->items()[0]; item.setRemoteId(rid); ItemModifyJob *store = new ItemModifyJob(item, this); store->disableRevisionCheck(); store->setIgnorePayload(true); // we only want to update the remote id AKVERIFYEXEC(store); ItemFetchJob *fetch = new ItemFetchJob(item, this); AKVERIFYEXEC(fetch); QCOMPARE(fetch->items().count(), 1); item = fetch->items().at(0); QEXPECT_FAIL("clear", "Clearing RID by clients is currently forbidden to avoid conflicts.", Continue); QCOMPARE(item.remoteId().toUtf8(), exprid.toUtf8()); // no longer pretend to be a resource rsel = new ResourceSelectJob(QString(), this); AKVERIFYEXEC(rsel); } void ItemStoreTest::testMultiPart() { ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); AKVERIFYEXEC(prefetchjob); QCOMPARE(prefetchjob->items().count(), 1); Item item = prefetchjob->items()[0]; item.setMimeType(QStringLiteral("application/octet-stream")); item.setPayload("testmailbody"); item.attribute(Item::AddIfMissing)->data = "extra"; // store item ItemModifyJob *sjob = new ItemModifyJob(item); AKVERIFYEXEC(sjob); ItemFetchJob *fjob = new ItemFetchJob(Item(1)); fjob->fetchScope().fetchAttribute(); fjob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items()[0]; QVERIFY(item.hasPayload()); QCOMPARE(item.payload(), QByteArray("testmailbody")); QVERIFY(item.hasAttribute()); QCOMPARE(item.attribute()->data, QByteArray("extra")); // clean up item.removeAttribute("EXTRA"); sjob = new ItemModifyJob(item); AKVERIFYEXEC(sjob); } void ItemStoreTest::testPartRemove() { ItemFetchJob *prefetchjob = new ItemFetchJob(Item(2)); AKVERIFYEXEC(prefetchjob); Item item = prefetchjob->items()[0]; item.setMimeType(QStringLiteral("application/octet-stream")); item.attribute(Item::AddIfMissing)->data = "extra"; // store item ItemModifyJob *sjob = new ItemModifyJob(item); AKVERIFYEXEC(sjob); // fetch item and its parts (should be RFC822, HEAD and EXTRA) ItemFetchJob *fjob = new ItemFetchJob(Item(2)); fjob->fetchScope().fetchFullPayload(); fjob->fetchScope().fetchAllAttributes(); fjob->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); item = fjob->items()[0]; QCOMPARE(item.attributes().count(), 2); QVERIFY(item.hasAttribute()); // remove a part item.removeAttribute(); sjob = new ItemModifyJob(item); AKVERIFYEXEC(sjob); // fetch item again (should only have RFC822 and HEAD left) ItemFetchJob *fjob2 = new ItemFetchJob(Item(2)); fjob2->fetchScope().fetchFullPayload(); fjob2->fetchScope().fetchAllAttributes(); fjob2->fetchScope().setCacheOnly(true); AKVERIFYEXEC(fjob2); QCOMPARE(fjob2->items().count(), 1); item = fjob2->items()[0]; QCOMPARE(item.attributes().count(), 1); QVERIFY(!item.hasAttribute()); } void ItemStoreTest::testRevisionCheck() { // fetch same item twice Item ref(2); ItemFetchJob *prefetchjob = new ItemFetchJob(ref); AKVERIFYEXEC(prefetchjob); QCOMPARE(prefetchjob->items().count(), 1); Item item1 = prefetchjob->items()[0]; Item item2 = prefetchjob->items()[0]; // store first item unmodified ItemModifyJob *sjob = new ItemModifyJob(item1); AKVERIFYEXEC(sjob); // store the first item with modifications (should work) item1.attribute(Item::AddIfMissing)->data = "random stuff 1"; sjob = new ItemModifyJob(item1, this); AKVERIFYEXEC(sjob); // try to store second item with modifications (should be detected as a conflict) item2.attribute(Item::AddIfMissing)->data = "random stuff 2"; ItemModifyJob *sjob2 = new ItemModifyJob(item2); sjob2->disableAutomaticConflictHandling(); QVERIFY(!sjob2->exec()); // fetch same again prefetchjob = new ItemFetchJob(ref); AKVERIFYEXEC(prefetchjob); item1 = prefetchjob->items()[0]; // delete item ItemDeleteJob *djob = new ItemDeleteJob(ref, this); AKVERIFYEXEC(djob); // try to store it sjob = new ItemModifyJob(item1); QVERIFY(!sjob->exec()); } void ItemStoreTest::testModificationTime() { Item item; item.setMimeType(QStringLiteral("text/directory")); QVERIFY(item.modificationTime().isNull()); ItemCreateJob *job = new ItemCreateJob(item, res1_foo); AKVERIFYEXEC(job); // The item should have a datetime set now. item = job->item(); QVERIFY(!item.modificationTime().isNull()); QDateTime initialDateTime = item.modificationTime(); // Fetch the same item again. Item item2(item.id()); ItemFetchJob *fjob = new ItemFetchJob(item2, this); AKVERIFYEXEC(fjob); item2 = fjob->items().first(); QCOMPARE(initialDateTime, item2.modificationTime()); // Lets wait at least a second, which is the resolution of mtime QTest::qWait(1000); // Modify the item item.attribute(Item::AddIfMissing)->data = "extra"; ItemModifyJob *mjob = new ItemModifyJob(item); AKVERIFYEXEC(mjob); // The item should still have a datetime set and that date should be somewhere // after the initialDateTime. item = mjob->item(); QVERIFY(!item.modificationTime().isNull()); QVERIFY(initialDateTime < item.modificationTime()); // Fetch the item after modification. Item item3(item.id()); ItemFetchJob *fjob2 = new ItemFetchJob(item3, this); AKVERIFYEXEC(fjob2); // item3 should have the same modification time as item. item3 = fjob2->items().first(); QCOMPARE(item3.modificationTime(), item.modificationTime()); // Clean up ItemDeleteJob *idjob = new ItemDeleteJob(item, this); AKVERIFYEXEC(idjob); } void ItemStoreTest::testRemoteIdRace() { // Create an item and store it Item item; item.setMimeType(QStringLiteral("text/directory")); ItemCreateJob *job = new ItemCreateJob(item, res1_foo); AKVERIFYEXEC(job); // Fetch the same item again. It should not have a remote Id yet, as the resource // is offline. // The remote id should be null, not only empty, so that item modify jobs with this // item don't overwrite the remote id. Item item2(job->item().id()); ItemFetchJob *fetchJob = new ItemFetchJob(item2); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().size(), 1); QVERIFY(fetchJob->items().first().remoteId().isEmpty()); } void ItemStoreTest::itemModifyJobShouldOnlySendModifiedAttributes() { // Given an item with an attribute (created on the server) Item item; item.setMimeType(QStringLiteral("text/directory")); item.attribute(Item::AddIfMissing)->data = "initial"; ItemCreateJob *job = new ItemCreateJob(item, res1_foo); AKVERIFYEXEC(job); item = job->item(); QCOMPARE(item.attributes().count(), 1); // When one job modifies this attribute, and another one does an unrelated change Item item1(item.id()); item1.attribute(Item::AddIfMissing)->data = "modified"; ItemModifyJob *mjob = new ItemModifyJob(item1); mjob->disableRevisionCheck(); AKVERIFYEXEC(mjob); item.setFlag("added_test_flag_1"); // this job shouldn't send the old attribute again ItemModifyJob *mjob2 = new ItemModifyJob(item); mjob2->disableRevisionCheck(); AKVERIFYEXEC(mjob2); // Then the item has the new value for the attribute (the other one didn't send the old attribute value) { auto *fetchJob = new ItemFetchJob(Item(item.id())); ItemFetchScope fetchScope; fetchScope.fetchAllAttributes(true); fetchJob->setFetchScope(fetchScope); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().size(), 1); const Item fetchedItem = fetchJob->items().first(); QCOMPARE(fetchedItem.flags().count(), 1); QCOMPARE(fetchedItem.attributes().count(), 1); QCOMPARE(fetchedItem.attribute()->data, "modified"); } } class ParallelJobsRunner { public: ParallelJobsRunner(int count) : numSessions(count) { sessions.reserve(numSessions); modifyJobs.reserve(numSessions); for (int i = 0 ; i < numSessions; ++i) { auto session = new Session(QByteArray::number(i)); sessions.push_back(session); } } ~ParallelJobsRunner() { qDeleteAll(sessions); } void addJob(ItemModifyJob *mjob) { modifyJobs.push_back(mjob); QObject::connect(mjob, &KJob::result, [mjob, this]() { if (mjob->error()) { errors.append(mjob->errorString()); } doneJobs.push_back(mjob); }); } void waitForAllJobs() { for (int i = 0 ; i < modifyJobs.count(); ++i) { ItemModifyJob *mjob = modifyJobs.at(i); if (!doneJobs.contains(mjob)) { QSignalSpy spy(mjob, &ItemModifyJob::result); QVERIFY(spy.wait()); if (mjob->error()) qWarning() << mjob->errorString(); QCOMPARE(mjob->error(), KJob::NoError); } } QVERIFY2(errors.isEmpty(), qPrintable(errors.join(QLatin1String("; ")))); } const int numSessions; std::vector sessions; QVector modifyJobs, doneJobs; QStringList errors; }; void ItemStoreTest::testParallelJobsAddingAttributes() { // Given an item (created on the server) Item::Id itemId; { Item item; item.setMimeType(QStringLiteral("text/directory")); ItemCreateJob *job = new ItemCreateJob(item, res1_foo); AKVERIFYEXEC(job); itemId = job->item().id(); QVERIFY(itemId >= 0); } // When adding N attributes from N different sessions (e.g. threads or processes) ParallelJobsRunner runner(10); for (int i = 0 ; i < runner.numSessions; ++i) { Item item(itemId); Attribute *attr = AttributeFactory::createAttribute("type" + QByteArray::number(i)); QVERIFY(attr); attr->deserialize("attr" + QByteArray::number(i)); item.addAttribute(attr); ItemModifyJob *mjob = new ItemModifyJob(item, runner.sessions.at(i)); runner.addJob(mjob); } runner.waitForAllJobs(); // Then the item should have all attributes ItemFetchJob *fetchJob = new ItemFetchJob(Item(itemId)); ItemFetchScope fetchScope; fetchScope.fetchAllAttributes(true); fetchJob->setFetchScope(fetchScope); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().size(), 1); const Item fetchedItem = fetchJob->items().first(); QCOMPARE(fetchedItem.attributes().count(), runner.numSessions); } diff --git a/autotests/libs/itemsynctest.cpp b/autotests/libs/itemsynctest.cpp index 17d931775..2a17382ca 100644 --- a/autotests/libs/itemsynctest.cpp +++ b/autotests/libs/itemsynctest.cpp @@ -1,707 +1,705 @@ /* Copyright (c) 2008 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" - #include "agentmanager.h" #include "agentinstance.h" #include "control.h" #include "collection.h" #include "item.h" #include "itemdeletejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemsync.h" #include "itemcreatejob.h" #include "qtest_akonadi.h" #include "monitor.h" #include "resourceselectjob_p.h" #include #include #include #include using namespace Akonadi; Q_DECLARE_METATYPE(KJob *) Q_DECLARE_METATYPE(ItemSync::TransactionMode) class ItemsyncTest : public QObject { Q_OBJECT private: Item::List fetchItems(const Collection &col) { qDebug() << "fetching items from collection" << col.remoteId() << col.name(); ItemFetchJob *fetch = new ItemFetchJob(col, this); fetch->fetchScope().fetchFullPayload(); fetch->fetchScope().fetchAllAttributes(); fetch->fetchScope().setCacheOnly(true); // resources are switched off anyway if (!fetch->exec()) { []() { QFAIL("Failed to fetch items!"); }(); } return fetch->items(); } static void createItems(const Collection &col, int itemCount) { for (int i = 0; i < itemCount; ++i) { Item item(QStringLiteral("application/octet-stream")); item.setRemoteId(QStringLiteral("rid") + QString::number(i)); item.setGid(QStringLiteral("gid") + QString::number(i)); item.setPayload("payload1"); ItemCreateJob *job = new ItemCreateJob(item, col); AKVERIFYEXEC(job); } } static Item duplicateItem(const Item &item, const Collection &col) { Item duplicate = item; duplicate.setId(-1); ItemCreateJob *job = new ItemCreateJob(duplicate, col); [job]() { AKVERIFYEXEC(job); }(); return job->item(); } static Item modifyItem(Item item) { static int counter = 0; item.setFlag(QByteArray("\\READ") + QByteArray::number(counter)); counter++; return item; } std::unique_ptr createCollectionMonitor(const Collection &col) { auto monitor = std::make_unique(); monitor->setCollectionMonitored(col); if (!AkonadiTest::akWaitForSignal(monitor.get(), &Monitor::monitorReady)) { QTest::qFail("Failed to wait for monitor", __FILE__, __LINE__); return nullptr; } return monitor; } private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AkonadiTest::setAllResourcesOffline(); qRegisterMetaType(); qRegisterMetaType(); } void testFullSync() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); //Since the item sync affects the knut resource we ensure we actually managed to load all items //This needs to be adjusted should the testdataset change QCOMPARE(origItems.size(), 15); Akonadi::Monitor monitor; monitor.setCollectionMonitored(col); QSignalSpy deletedSpy(&monitor, &Monitor::itemRemoved); QVERIFY(deletedSpy.isValid()); QSignalSpy addedSpy(&monitor, &Monitor::itemAdded); QVERIFY(addedSpy.isValid()); QSignalSpy changedSpy(&monitor, &Monitor::itemChanged); QVERIFY(changedSpy.isValid()); ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setFullSyncItems(origItems); AKVERIFYEXEC(syncer); QCOMPARE(transactionSpy.count(), 1); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); QTest::qWait(100); QCOMPARE(deletedSpy.count(), 0); QCOMPARE(addedSpy.count(), 0); QCOMPARE(changedSpy.count(), 0); } void testFullStreamingSync_data() { QTest::addColumn("transactionMode"); QTest::addColumn("goToEventLoopAfterAddingItems"); QTest::newRow("single transaction, no eventloop") << ItemSync::SingleTransaction << false; QTest::newRow("multi transaction, no eventloop") << ItemSync::MultipleTransactions << false; QTest::newRow("single transaction, with eventloop") << ItemSync::SingleTransaction << true; QTest::newRow("multi transaction, with eventloop") << ItemSync::MultipleTransactions << true; } void testFullStreamingSync() { QFETCH(ItemSync::TransactionMode, transactionMode); QFETCH(bool, goToEventLoopAfterAddingItems); - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); QCOMPARE(origItems.size(), 15); auto monitor = createCollectionMonitor(col); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); ItemSync *syncer = new ItemSync(col); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setTransactionMode(transactionMode); syncer->setBatchSize(1); syncer->setAutoDelete(false); syncer->setStreamingEnabled(true); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setTotalItems(origItems.count()); QTest::qWait(0); QCOMPARE(spy.count(), 0); for (int i = 0; i < origItems.count(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setFullSyncItems(l); if (goToEventLoopAfterAddingItems) { QTest::qWait(0); } if (i < origItems.count() - 1) { QCOMPARE(spy.count(), 0); } } syncer->deliveryDone(); QTRY_COMPARE(spy.count(), 1); KJob *job = spy.at(0).at(0).value(); QCOMPARE(job, syncer); QCOMPARE(job->error(), 0); if (transactionMode == ItemSync::SingleTransaction) { QCOMPARE(transactionSpy.count(), 1); } if (transactionMode == ItemSync::MultipleTransactions) { QCOMPARE(transactionSpy.count(), origItems.count()); } Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); delete syncer; QTest::qWait(100); QTRY_COMPARE(deletedSpy.count(), 0); QTRY_COMPARE(addedSpy.count(), 0); QTRY_COMPARE(changedSpy.count(), origItems.count()); } void testIncrementalSync() { { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); } - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); QCOMPARE(origItems.size(), 15); auto monitor = createCollectionMonitor(col); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); { ItemSync *syncer = new ItemSync(col); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setTransactionMode(ItemSync::SingleTransaction); syncer->setIncrementalSyncItems(origItems, Item::List()); AKVERIFYEXEC(syncer); QCOMPARE(transactionSpy.count(), 1); } QTest::qWait(100); QTRY_COMPARE(deletedSpy.count(), 0); QCOMPARE(addedSpy.count(), 0); QTRY_COMPARE(changedSpy.count(), 0); deletedSpy.clear(); addedSpy.clear(); changedSpy.clear(); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); Item::List delItems; delItems << resultItems.takeFirst(); Item itemWithOnlyRemoteId; itemWithOnlyRemoteId.setRemoteId(resultItems.front().remoteId()); delItems << itemWithOnlyRemoteId; resultItems.takeFirst(); //This item will not be removed since it isn't existing locally Item itemWithRandomRemoteId; itemWithRandomRemoteId.setRemoteId(KRandom::randomString(100)); delItems << itemWithRandomRemoteId; { ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setIncrementalSyncItems(resultItems, delItems); AKVERIFYEXEC(syncer); QCOMPARE(transactionSpy.count(), 1); } Item::List resultItems2 = fetchItems(col); QCOMPARE(resultItems2.count(), resultItems.count()); QTest::qWait(100); QTRY_COMPARE(deletedSpy.count(), 2); QCOMPARE(addedSpy.count(), 0); QTRY_COMPARE(changedSpy.count(), 0); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); AKVERIFYEXEC(select); } } void testIncrementalStreamingSync() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); auto monitor = createCollectionMonitor(col); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setAutoDelete(false); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setStreamingEnabled(true); QTest::qWait(0); QCOMPARE(spy.count(), 0); for (int i = 0; i < origItems.count(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setIncrementalSyncItems(l, Item::List()); if (i < origItems.count() - 1) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } syncer->deliveryDone(); QTRY_COMPARE(spy.count(), 1); KJob *job = spy.at(0).at(0).value(); QCOMPARE(job, syncer); QCOMPARE(job->error(), 0); QCOMPARE(transactionSpy.count(), 1); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); delete syncer; QTest::qWait(100); QCOMPARE(deletedSpy.count(), 0); QCOMPARE(addedSpy.count(), 0); QTRY_COMPARE(changedSpy.count(), origItems.size()); } void testEmptyIncrementalSync() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); auto monitor = createCollectionMonitor(col); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setIncrementalSyncItems(Item::List(), Item::List()); AKVERIFYEXEC(syncer); //It would be better if we didn't have a transaction at all, but so far the transaction is still created QCOMPARE(transactionSpy.count(), 1); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); QTest::qWait(100); QCOMPARE(deletedSpy.count(), 0); QCOMPARE(addedSpy.count(), 0); QCOMPARE(changedSpy.count(), 0); } void testIncrementalStreamingSyncBatchProcessing() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); auto monitor = createCollectionMonitor(col); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); ItemSync *syncer = new ItemSync(col); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setStreamingEnabled(true); syncer->setTransactionMode(ItemSync::MultipleTransactions); QTest::qWait(0); QCOMPARE(spy.count(), 0); for (int i = 0; i < syncer->batchSize(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setIncrementalSyncItems(l, Item::List()); if (i < (syncer->batchSize() - 1)) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } QTest::qWait(100); //this should process one batch of batchSize() items QTRY_COMPARE(changedSpy.count(), syncer->batchSize()); QCOMPARE(transactionSpy.count(), 1); //one per batch for (int i = syncer->batchSize(); i < origItems.count(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setIncrementalSyncItems(l, Item::List()); if (i < origItems.count() - 1) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } syncer->deliveryDone(); QTRY_COMPARE(spy.count(), 1); QCOMPARE(transactionSpy.count(), 2); //one per batch QTest::qWait(100); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); QTest::qWait(100); QCOMPARE(deletedSpy.count(), 0); QCOMPARE(addedSpy.count(), 0); QTRY_COMPARE(changedSpy.count(), resultItems.count()); } void testGidMerge() { - Collection col(collectionIdFromPath(QStringLiteral("res3"))); + Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); { Item item(QStringLiteral("application/octet-stream")); item.setRemoteId(QStringLiteral("rid1")); item.setGid(QStringLiteral("gid1")); item.setPayload("payload1"); ItemCreateJob *job = new ItemCreateJob(item, col); AKVERIFYEXEC(job); } { Item item(QStringLiteral("application/octet-stream")); item.setRemoteId(QStringLiteral("rid2")); item.setGid(QStringLiteral("gid2")); item.setPayload("payload1"); ItemCreateJob *job = new ItemCreateJob(item, col); AKVERIFYEXEC(job); } Item modifiedItem(QStringLiteral("application/octet-stream")); modifiedItem.setRemoteId(QStringLiteral("rid3")); modifiedItem.setGid(QStringLiteral("gid2")); modifiedItem.setPayload("payload2"); ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::MultipleTransactions); syncer->setIncrementalSyncItems(Item::List() << modifiedItem, Item::List()); AKVERIFYEXEC(syncer); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), 3); Item item; item.setGid(QStringLiteral("gid2")); ItemFetchJob *fetchJob = new ItemFetchJob(item); fetchJob->fetchScope().fetchFullPayload(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().size(), 2); QCOMPARE(fetchJob->items().first().payload(), QByteArray("payload2")); QCOMPARE(fetchJob->items().first().remoteId(), QString::fromLatin1("rid3")); QCOMPARE(fetchJob->items().at(1).payload(), QByteArray("payload1")); QCOMPARE(fetchJob->items().at(1).remoteId(), QStringLiteral("rid2")); } /* * This test verifies that ItemSync doesn't prematurely emit its result if a job inside a transaction fails. * ItemSync is supposed to continue the sync but simply ignoring all delivered data. */ void testFailingJob() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); ItemSync *syncer = new ItemSync(col); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setStreamingEnabled(true); syncer->setTransactionMode(ItemSync::MultipleTransactions); QTest::qWait(0); QCOMPARE(spy.count(), 0); for (int i = 0; i < syncer->batchSize(); ++i) { Item::List l; //Modify to trigger a changed signal Item item = modifyItem(origItems[i]); // item.setRemoteId(QByteArray("foo")); item.setRemoteId(QString()); item.setId(-1); l << item; syncer->setIncrementalSyncItems(l, Item::List()); if (i < (syncer->batchSize() - 1)) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } QTest::qWait(100); QTRY_COMPARE(spy.count(), 0); for (int i = syncer->batchSize(); i < origItems.count(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setIncrementalSyncItems(l, Item::List()); if (i < origItems.count() - 1) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } syncer->deliveryDone(); QTRY_COMPARE(spy.count(), 1); } /* * This test verifies that ItemSync doesn't prematurely emit its result if a job inside a transaction fails, due to a duplicate. * This case used to break the TransactionSequence. * ItemSync is supposed to continue the sync but simply ignoring all delivered data. */ void testFailingDueToDuplicateItem() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); //Create a duplicate that will trigger an error during the first batch Item dupe = duplicateItem(origItems.at(0), col); origItems = fetchItems(col); ItemSync *syncer = new ItemSync(col); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); QSignalSpy spy(syncer, &KJob::result); QVERIFY(spy.isValid()); syncer->setStreamingEnabled(true); syncer->setTransactionMode(ItemSync::MultipleTransactions); QTest::qWait(0); QCOMPARE(spy.count(), 0); for (int i = 0; i < syncer->batchSize(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setIncrementalSyncItems(l, Item::List()); if (i < (syncer->batchSize() - 1)) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } QTest::qWait(100); //Ensure the job hasn't finished yet due to the errors QTRY_COMPARE(spy.count(), 0); for (int i = syncer->batchSize(); i < origItems.count(); ++i) { Item::List l; //Modify to trigger a changed signal l << modifyItem(origItems[i]); syncer->setIncrementalSyncItems(l, Item::List()); if (i < origItems.count() - 1) { QTest::qWait(0); // enter the event loop so itemsync actually can do something } QCOMPARE(spy.count(), 0); } syncer->deliveryDone(); QTRY_COMPARE(spy.count(), 1); // cleanup ItemDeleteJob *del = new ItemDeleteJob(dupe, this); AKVERIFYEXEC(del); } void testFullSyncFailingDueToDuplicateItem() { - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); QVERIFY(col.isValid()); Item::List origItems = fetchItems(col); //Create a duplicate that will trigger an error during the first batch Item dupe = duplicateItem(origItems.at(0), col); origItems = fetchItems(col); auto monitor = createCollectionMonitor(col); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setFullSyncItems(origItems); QVERIFY(!syncer->exec()); QCOMPARE(transactionSpy.count(), 1); Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); QTest::qWait(100); //QCOMPARE(deletedSpy.count(), 1); // ## is this correct? //QCOMPARE(addedSpy.count(), 1); // ## is this correct? QCOMPARE(changedSpy.count(), 0); // cleanup ItemDeleteJob *del = new ItemDeleteJob(dupe, this); AKVERIFYEXEC(del); } void testFullSyncManyItems() { // Given a collection with 1000 items - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/foo2"))); QVERIFY(col.isValid()); auto monitor = createCollectionMonitor(col); QSignalSpy addedSpy(monitor.get(), &Monitor::itemAdded); const int itemCount = 1000; createItems(col, itemCount); QTRY_COMPARE(addedSpy.count(), itemCount); addedSpy.clear(); const Item::List origItems = fetchItems(col); QCOMPARE(origItems.size(), itemCount); QSignalSpy deletedSpy(monitor.get(), &Monitor::itemRemoved); QSignalSpy changedSpy(monitor.get(), &Monitor::itemChanged); QBENCHMARK { ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); QSignalSpy transactionSpy(syncer, &ItemSync::transactionCommitted); QVERIFY(transactionSpy.isValid()); syncer->setFullSyncItems(origItems); AKVERIFYEXEC(syncer); QCOMPARE(transactionSpy.count(), 1); } const Item::List resultItems = fetchItems(col); QCOMPARE(resultItems.count(), origItems.count()); QTest::qWait(100); QCOMPARE(deletedSpy.count(), 0); QCOMPARE(addedSpy.count(), 0); QCOMPARE(changedSpy.count(), 0); // delete all items; QBENCHMARK leads to the whole method being called more than once ItemDeleteJob *job = new ItemDeleteJob(resultItems); AKVERIFYEXEC(job); } void testUserCancel() { // Given a collection with 100 items - const Collection col = Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + const Collection col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/foo2"))); QVERIFY(col.isValid()); const Item::List itemsToDelete = fetchItems(col); if (!itemsToDelete.isEmpty()) { ItemDeleteJob *deleteJob = new ItemDeleteJob(itemsToDelete); AKVERIFYEXEC(deleteJob); } const int itemCount = 100; createItems(col, itemCount); const Item::List origItems = fetchItems(col); QCOMPARE(origItems.size(), itemCount); // and an ItemSync running ItemSync *syncer = new ItemSync(col); syncer->setTransactionMode(ItemSync::SingleTransaction); syncer->setFullSyncItems(origItems); // When the user cancels the ItemSync QTimer::singleShot(10, syncer, &ItemSync::rollback); // Then the itemsync should finish at some point, and not crash QVERIFY(!syncer->exec()); QCOMPARE(syncer->errorString(), QStringLiteral("User canceled operation.")); // Cleanup ItemDeleteJob *job = new ItemDeleteJob(origItems); AKVERIFYEXEC(job); } }; QTEST_AKONADIMAIN(ItemsyncTest) #include "itemsynctest.moc" diff --git a/autotests/libs/lazypopulationtest.cpp b/autotests/libs/lazypopulationtest.cpp index 4bf547bf6..08188e428 100644 --- a/autotests/libs/lazypopulationtest.cpp +++ b/autotests/libs/lazypopulationtest.cpp @@ -1,371 +1,369 @@ /* Copyright (c) 2013 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include "test_utils.h" - #include "entitytreemodel.h" #include "control.h" #include "entitytreemodel_p.h" #include "monitor_p.h" #include "changerecorder_p.h" #include "qtest_akonadi.h" #include "collectioncreatejob.h" #include "itemcreatejob.h" using namespace Akonadi; class InspectableETM: public EntityTreeModel { public: explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr) : EntityTreeModel(monitor, parent) {} EntityTreeModelPrivate *etmPrivate() { return d_ptr; } }; /** * This is a test for the LazyPopulation of the ETM and the associated refcounting in the Monitor. */ class LazyPopulationTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); /** * Test a complete scenario that checks: * * loading on referencing * * buffering after referencing * * purging after the collection leaves the buffer * * not-fetching when a collection is not buffered and not referenced * * reloading after a collection becomes referenced again */ void testItemAdded(); /* * Test what happens if we * * Create an item * * Reference before item added signal arrives * * Try fetching rest of items */ void testItemAddedBeforeFetch(); /* * We purge an empty collection and make sure it can be fetched later on. * * reference collection to remember empty status * * purge collection * * add item (it should not be added since not monitored) * * reference collection and make sure items are added */ void testPurgeEmptyCollection(); private: Collection res3; static const int numberOfRootCollections = 4; static const int bufferSize; }; const int LazyPopulationTest::bufferSize = MonitorPrivate::PurgeBuffer::buffersize(); void LazyPopulationTest::initTestCase() { qRegisterMetaType("Akonadi::Collection::Id"); AkonadiTest::checkTestIsIsolated(); AkonadiTest::setAllResourcesOffline(); - res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); //Set up a bunch of collections that we can select to purge a collection from the buffer //Number of buffered collections in the monitor const int bufferSize = MonitorPrivate::PurgeBuffer::buffersize(); for (int i = 0; i < bufferSize; i++) { Collection col; col.setParentCollection(res3); col.setName(QStringLiteral("col%1").arg(i)); CollectionCreateJob *create = new CollectionCreateJob(col, this); AKVERIFYEXEC(create); } } QModelIndex getIndex(const QString &string, EntityTreeModel *model) { QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive); if (list.isEmpty()) { return QModelIndex(); } return list.first(); } /** * Since we have no sensible way to figure out if the model is fully populated, * we use the brute force approach. */ bool waitForPopulation(const QModelIndex &idx, EntityTreeModel *model, int count) { for (int i = 0; i < 500; i++) { if (model->rowCount(idx) >= count) { return true; } QTest::qWait(10); } return false; } void referenceCollection(EntityTreeModel *model, int index) { QModelIndex idx = getIndex(QStringLiteral("col%1").arg(index), model); QVERIFY(idx.isValid()); model->setData(idx, QVariant(), EntityTreeModel::CollectionRefRole); model->setData(idx, QVariant(), EntityTreeModel::CollectionDerefRole); } void referenceCollections(EntityTreeModel *model, int count) { for (int i = 0; i < count; i++) { referenceCollection(model, i); } } void LazyPopulationTest::testItemAdded() { const int bufferSize = MonitorPrivate::PurgeBuffer::buffersize(); const QString mainCollectionName(QStringLiteral("main")); Collection monitorCol; { monitorCol.setParentCollection(res3); monitorCol.setName(mainCollectionName); CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); AKVERIFYEXEC(create); monitorCol = create->collection(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, monitorCol, this); AKVERIFYEXEC(append); item1 = append->item(); } ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(Collection::root()); QVERIFY(AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady)); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); //Wait for initial listing to complete QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); QVERIFY(waitForPopulation(res3Index, model, bufferSize + 1)); QModelIndex monitorIndex = getIndex(mainCollectionName, model); QVERIFY(monitorIndex.isValid()); //Start //---Check that the item is present after the collection was referenced model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); model->fetchMore(monitorIndex); //Wait for collection to be fetched QVERIFY(waitForPopulation(monitorIndex, model, 1)); //---ensure we cannot fetchMore again QVERIFY(!model->etmPrivate()->canFetchMore(monitorIndex)); //The item should now be present QCOMPARE(model->index(0, 0, monitorIndex).data(Akonadi::EntityTreeModel::ItemIdRole).value(), item1.id()); //---ensure item1 is still available after no longer being referenced due to buffering model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionDerefRole); QCOMPARE(model->index(0, 0, monitorIndex).data(Akonadi::EntityTreeModel::ItemIdRole).value(), item1.id()); //---ensure item1 gets purged after the collection is no longer buffered //Get the monitorCol out of the buffer referenceCollections(model, bufferSize - 1); //The collection is still in the buffer... QCOMPARE(model->rowCount(monitorIndex), 1); referenceCollection(model, bufferSize - 1); //...and now purged QCOMPARE(model->rowCount(monitorIndex), 0); QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); //---ensure item2 added to unbuffered and unreferenced collection is not added to the model Item item2; { item2.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item2, monitorCol, this); AKVERIFYEXEC(append); item2 = append->item(); } QCOMPARE(model->rowCount(monitorIndex), 0); //---ensure all items are loaded after re-referencing the collection model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); model->fetchMore(monitorIndex); //Wait for collection to be fetched QVERIFY(waitForPopulation(monitorIndex, model, 2)); QCOMPARE(model->rowCount(monitorIndex), 2); QVERIFY(!model->etmPrivate()->canFetchMore(monitorIndex)); //purge collection again model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionDerefRole); referenceCollections(model, bufferSize); QCOMPARE(model->rowCount(monitorIndex), 0); //fetch when not monitored QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); model->fetchMore(monitorIndex); QVERIFY(waitForPopulation(monitorIndex, model, 2)); //ensure we cannot refetch QVERIFY(!model->etmPrivate()->canFetchMore(monitorIndex)); } void LazyPopulationTest::testItemAddedBeforeFetch() { const QString mainCollectionName(QStringLiteral("main2")); Collection monitorCol; { monitorCol.setParentCollection(res3); monitorCol.setName(mainCollectionName); CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); AKVERIFYEXEC(create); monitorCol = create->collection(); } ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(Collection::root()); QVERIFY(AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady)); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); //Wait for initial listing to complete QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); QVERIFY(waitForPopulation(res3Index, model, bufferSize + 1)); QModelIndex monitorIndex = getIndex(mainCollectionName, model); QVERIFY(monitorIndex.isValid()); //Create a first item before referencing, it should not show up in the ETM { Item item1; item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, monitorCol, this); AKVERIFYEXEC(append); } //Before referenced or fetchMore is called, the collection should be empty QTest::qWait(500); QCOMPARE(model->rowCount(monitorIndex), 0); //Reference the collection QVERIFY(!model->etmPrivate()->isMonitored(monitorCol.id())); model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); QVERIFY(model->etmPrivate()->isMonitored(monitorCol.id())); //Create another item, it should not be added to the ETM although the signal is emitted from the monitor, but we should be able to fetchMore { QSignalSpy addedSpy(changeRecorder, &Monitor::itemAdded); QVERIFY(addedSpy.isValid()); Item item2; item2.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item2, monitorCol, this); AKVERIFYEXEC(append); QTRY_VERIFY(addedSpy.count() >= 1); } QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); model->fetchMore(monitorIndex); //Wait for collection to be fetched QVERIFY(waitForPopulation(monitorIndex, model, 2)); } void LazyPopulationTest::testPurgeEmptyCollection() { const QString mainCollectionName(QStringLiteral("main3")); Collection monitorCol; { monitorCol.setParentCollection(res3); monitorCol.setName(mainCollectionName); CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); AKVERIFYEXEC(create); monitorCol = create->collection(); } //Monitor without referencing so we get all signals Monitor *monitor = new Monitor(this); monitor->setCollectionMonitored(Collection::root()); QVERIFY(AkonadiTest::akWaitForSignal(monitor, &Monitor::monitorReady)); ChangeRecorder *changeRecorder = new ChangeRecorder(this); changeRecorder->setCollectionMonitored(Collection::root()); QVERIFY(AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady)); InspectableETM *model = new InspectableETM(changeRecorder, this); model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); //Wait for initial listing to complete QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); QVERIFY(waitForPopulation(res3Index, model, bufferSize + 1)); QModelIndex monitorIndex = getIndex(mainCollectionName, model); QVERIFY(monitorIndex.isValid()); //fetch the collection so we remember the empty status QSignalSpy populatedSpy(model, &EntityTreeModel::collectionPopulated); model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); model->fetchMore(monitorIndex); //Wait for collection to be fetched QTRY_VERIFY(populatedSpy.count() >= 1); //get the collection purged model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionDerefRole); referenceCollections(model, bufferSize); //create an item { QSignalSpy addedSpy(monitor, &Monitor::itemAdded); QVERIFY(addedSpy.isValid()); Item item1; item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, monitorCol, this); AKVERIFYEXEC(append); QTRY_VERIFY(addedSpy.count() >= 1); } //ensure it's not in the model //fetch the collection QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); model->fetchMore(monitorIndex); //Wait for collection to be fetched QVERIFY(waitForPopulation(monitorIndex, model, 1)); } #include "lazypopulationtest.moc" QTEST_AKONADIMAIN(LazyPopulationTest) diff --git a/autotests/libs/monitortest.cpp b/autotests/libs/monitortest.cpp index 9ddacdd22..cc0ea0d28 100644 --- a/autotests/libs/monitortest.cpp +++ b/autotests/libs/monitortest.cpp @@ -1,416 +1,415 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "monitortest.h" -#include "test_utils.h" #include "agentmanager.h" #include "agentinstance.h" #include "monitor.h" #include "collectioncreatejob.h" #include "collectiondeletejob.h" #include "collectionfetchjob.h" #include "collectionmodifyjob.h" #include "collectionmovejob.h" #include "collectionstatistics.h" #include "control.h" #include "itemcreatejob.h" #include "itemdeletejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemmodifyjob.h" #include "itemmovejob.h" #include "searchcreatejob.h" #include "searchquery.h" #include "subscriptionjob_p.h" #include "qtest_akonadi.h" #include #include using namespace Akonadi; QTEST_AKONADIMAIN(MonitorTest) static Collection res3; Q_DECLARE_METATYPE(Akonadi::Collection::Id) Q_DECLARE_METATYPE(QSet) void MonitorTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); - res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); AkonadiTest::setAllResourcesOffline(); } void MonitorTest::testMonitor_data() { QTest::addColumn("fetchCol"); QTest::newRow("with collection fetching") << true; QTest::newRow("without collection fetching") << false; } void MonitorTest::testMonitor() { QFETCH(bool, fetchCol); Monitor monitor; monitor.setCollectionMonitored(Collection::root()); monitor.fetchCollection(fetchCol); monitor.itemFetchScope().fetchFullPayload(); monitor.itemFetchScope().setCacheOnly(true); QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); // monitor signals qRegisterMetaType(); /* qRegisterMetaType() registers the type with a name of "qlonglong". Doing qRegisterMetaType( "Akonadi::Collection::Id" ) doesn't help. (works now , see QTBUG-937 and QTBUG-6833, -- dvratil) The problem here is that Akonadi::Collection::Id is a typedef to qlonglong, and qlonglong is already a registered meta type. So the signal spy will give us a QVariant of type Akonadi::Collection::Id, but calling .value() on that variant will in fact end up calling qvariant_cast. From the point of view of QMetaType, Akonadi::Collection::Id and qlonglong are different types, so QVariant can't convert, and returns a default-constructed qlonglong, zero. When connecting to a real slot (without QSignalSpy), this problem is avoided, because the casting is done differently (via a lot of void pointers). The docs say nothing about qRegisterMetaType -ing a typedef, so I'm not sure if this is a bug or not. (cberzan) */ qRegisterMetaType("Akonadi::Collection::Id"); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType >(); QSignalSpy caddspy(&monitor, &Monitor::collectionAdded); QSignalSpy cmodspy(&monitor, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); QSignalSpy cmvspy(&monitor, &Monitor::collectionMoved); QSignalSpy crmspy(&monitor, &Monitor::collectionRemoved); QSignalSpy cstatspy(&monitor, &Monitor::collectionStatisticsChanged); QSignalSpy cSubscribedSpy(&monitor, &Monitor::collectionSubscribed); QSignalSpy cUnsubscribedSpy(&monitor, &Monitor::collectionUnsubscribed); QSignalSpy iaddspy(&monitor, &Monitor::itemAdded); QSignalSpy imodspy(&monitor, &Monitor::itemChanged); QSignalSpy imvspy(&monitor, &Monitor::itemMoved); QSignalSpy irmspy(&monitor, &Monitor::itemRemoved); QVERIFY(caddspy.isValid()); QVERIFY(cmodspy.isValid()); QVERIFY(cmvspy.isValid()); QVERIFY(crmspy.isValid()); QVERIFY(cstatspy.isValid()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isValid()); QVERIFY(imodspy.isValid()); QVERIFY(imvspy.isValid()); QVERIFY(irmspy.isValid()); // create a collection Collection monitorCol; monitorCol.setParentCollection(res3); monitorCol.setName(QStringLiteral("monitor")); CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); AKVERIFYEXEC(create); monitorCol = create->collection(); QVERIFY(monitorCol.isValid()); QTRY_COMPARE(caddspy.count(), 1); QList arg = caddspy.takeFirst(); Collection col = arg.at(0).value(); QCOMPARE(col, monitorCol); if (fetchCol) { QCOMPARE(col.name(), QStringLiteral("monitor")); } Collection parent = arg.at(1).value(); QCOMPARE(parent, res3); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cstatspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // add an item Item newItem; newItem.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(newItem, monitorCol, this); AKVERIFYEXEC(append); Item monitorRef = append->item(); QVERIFY(monitorRef.isValid()); QTRY_COMPARE(cstatspy.count(), 1); arg = cstatspy.takeFirst(); QCOMPARE(arg.at(0).value(), monitorCol.id()); QCOMPARE(iaddspy.count(), 1); arg = iaddspy.takeFirst(); Item item = arg.at(0).value(); QCOMPARE(item, monitorRef); QCOMPARE(item.mimeType(), QString::fromLatin1("application/octet-stream")); Collection collection = arg.at(1).value(); QCOMPARE(collection.id(), monitorCol.id()); QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // modify an item item.setPayload("some new content"); ItemModifyJob *store = new ItemModifyJob(item, this); AKVERIFYEXEC(store); QTRY_COMPARE(cstatspy.count(), 1); arg = cstatspy.takeFirst(); QCOMPARE(arg.at(0).value(), monitorCol.id()); QCOMPARE(imodspy.count(), 1); arg = imodspy.takeFirst(); item = arg.at(0).value(); QCOMPARE(monitorRef, item); QVERIFY(item.hasPayload()); QCOMPARE(item.payload(), QByteArray("some new content")); QSet parts = arg.at(1).value >(); QCOMPARE(parts, QSet() << "PLD:RFC822"); QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // move an item ItemMoveJob *move = new ItemMoveJob(item, res3); AKVERIFYEXEC(move); QTRY_COMPARE(cstatspy.count(), 2); // NOTE: We don't make any assumptions about the order of the collectionStatisticsChanged // signals, they seem to arrive in random order QList notifiedCols; notifiedCols << cstatspy.takeFirst().at(0).value() << cstatspy.takeFirst().at(0).value(); QVERIFY(notifiedCols.contains(res3.id())); // destination QVERIFY(notifiedCols.contains(monitorCol.id())); // source QCOMPARE(imvspy.count(), 1); arg = imvspy.takeFirst(); item = arg.at(0).value(); // the item QCOMPARE(monitorRef, item); col = arg.at(1).value(); // the source collection QCOMPARE(col.id(), monitorCol.id()); col = arg.at(2).value(); // the destination collection QCOMPARE(col.id(), res3.id()); QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // delete an item ItemDeleteJob *del = new ItemDeleteJob(monitorRef, this); AKVERIFYEXEC(del); QTRY_COMPARE(cstatspy.count(), 1); arg = cstatspy.takeFirst(); QCOMPARE(arg.at(0).value(), res3.id()); cmodspy.clear(); QCOMPARE(irmspy.count(), 1); arg = irmspy.takeFirst(); Item ref = qvariant_cast(arg.at(0)); QCOMPARE(monitorRef, ref); QCOMPARE(ref.parentCollection(), res3); QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); imvspy.clear(); // Unsubscribe and re-subscribed a collection that existed before the monitor was created. - Collection subCollection = Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + Collection subCollection = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/foo2"))); subCollection.setName(QStringLiteral("foo2")); QVERIFY(subCollection.isValid()); SubscriptionJob *subscribeJob = new SubscriptionJob(this); subscribeJob->unsubscribe(Collection::List() << subCollection); AKVERIFYEXEC(subscribeJob); // Wait for unsubscribed signal, it goes after changed, so we can check for both QTRY_COMPARE(cmodspy.size(), 1); arg = cmodspy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col.id(), subCollection.id()); QVERIFY(cSubscribedSpy.isEmpty()); QTRY_COMPARE(cUnsubscribedSpy.size(), 1); arg = cUnsubscribedSpy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col.id(), subCollection.id()); subscribeJob = new SubscriptionJob(this); subscribeJob->subscribe(Collection::List() << subCollection); AKVERIFYEXEC(subscribeJob); // Wait for subscribed signal, it goes after changed, so we can check for both QTRY_COMPARE(cmodspy.size(), 1); arg = cmodspy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col.id(), subCollection.id()); QVERIFY(cUnsubscribedSpy.isEmpty()); QTRY_COMPARE(cSubscribedSpy.size(), 1); arg = cSubscribedSpy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col.id(), subCollection.id()); if (fetchCol) { QVERIFY(!col.name().isEmpty()); QCOMPARE(col.name(), subCollection.name()); } QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cstatspy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // modify a collection monitorCol.setName(QStringLiteral("changed name")); CollectionModifyJob *mod = new CollectionModifyJob(monitorCol, this); AKVERIFYEXEC(mod); QTRY_COMPARE(cmodspy.count(), 1); arg = cmodspy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col, monitorCol); if (fetchCol) { QCOMPARE(col.name(), QStringLiteral("changed name")); } QVERIFY(caddspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cstatspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // move a collection - Collection dest = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + Collection dest = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo"))); CollectionMoveJob *cmove = new CollectionMoveJob(monitorCol, dest, this); AKVERIFYEXEC(cmove); QTRY_COMPARE(cmvspy.count(), 1); arg = cmvspy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col, monitorCol); QCOMPARE(col.parentCollection(), dest); if (fetchCol) { QCOMPARE(col.name(), monitorCol.name()); } col = arg.at(1).value(); QCOMPARE(col, res3); col = arg.at(2).value(); QCOMPARE(col, dest); QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(crmspy.isEmpty()); QVERIFY(cstatspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); // delete a collection CollectionDeleteJob *cdel = new CollectionDeleteJob(monitorCol, this); AKVERIFYEXEC(cdel); QTRY_COMPARE(crmspy.count(), 1); arg = crmspy.takeFirst(); col = arg.at(0).value(); QCOMPARE(col.id(), monitorCol.id()); QCOMPARE(col.parentCollection(), dest); QVERIFY(caddspy.isEmpty()); QVERIFY(cmodspy.isEmpty()); QVERIFY(cmvspy.isEmpty()); QVERIFY(cstatspy.isEmpty()); QVERIFY(cSubscribedSpy.isEmpty()); QVERIFY(cUnsubscribedSpy.isEmpty()); QVERIFY(iaddspy.isEmpty()); QVERIFY(imodspy.isEmpty()); QVERIFY(imvspy.isEmpty()); QVERIFY(irmspy.isEmpty()); } void MonitorTest::testVirtualCollectionsMonitoring() { Monitor monitor; monitor.setCollectionMonitored(Collection(1)); // top-level 'Search' collection QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); QSignalSpy caddspy(&monitor, &Monitor::collectionAdded); SearchCreateJob *job = new SearchCreateJob(QStringLiteral("Test search collection"), Akonadi::SearchQuery(), this); AKVERIFYEXEC(job); QTRY_COMPARE(caddspy.count(), 1); } diff --git a/autotests/libs/protocolhelpertest.cpp b/autotests/libs/protocolhelpertest.cpp index 56dd3a57d..3243310bb 100644 --- a/autotests/libs/protocolhelpertest.cpp +++ b/autotests/libs/protocolhelpertest.cpp @@ -1,333 +1,333 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" #include "protocolhelper.cpp" #include "attributestorage.cpp" +#include "qtest_akonadi.h" using namespace Akonadi; Q_DECLARE_METATYPE(Scope) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(Protocol::ItemFetchScope) class ProtocolHelperTest : public QObject { Q_OBJECT private Q_SLOTS: void testItemSetToByteArray_data() { QTest::addColumn("items"); QTest::addColumn("result"); QTest::addColumn("shouldThrow"); Item u1; u1.setId(1); Item u2; u2.setId(2); Item u3; u3.setId(3); Item r1; r1.setRemoteId(QStringLiteral("A")); Item r2; r2.setRemoteId(QStringLiteral("B")); Item h1; h1.setRemoteId(QStringLiteral("H1")); h1.setParentCollection(Collection::root()); Item h2; h2.setRemoteId(QStringLiteral("H2a")); h2.parentCollection().setRemoteId(QStringLiteral("H2b")); h2.parentCollection().setParentCollection(Collection::root()); Item h3; h3.setRemoteId(QStringLiteral("H3a")); h3.parentCollection().setRemoteId(QStringLiteral("H3b")); QTest::newRow("empty") << Item::List() << Scope() << true; QTest::newRow("single uid") << (Item::List() << u1) << Scope(1) << false; QTest::newRow("multi uid") << (Item::List() << u1 << u3) << Scope(QVector { 1, 3 }) << false; QTest::newRow("block uid") << (Item::List() << u1 << u2 << u3) << Scope(ImapInterval(1, 3)) << false; QTest::newRow("single rid") << (Item::List() << r1) << Scope(Scope::Rid, { QStringLiteral("A") }) << false; QTest::newRow("multi rid") << (Item::List() << r1 << r2) << Scope(Scope::Rid, { QStringLiteral("A"), QStringLiteral("B") }) << false; QTest::newRow("invalid") << (Item::List() << Item()) << Scope() << true; QTest::newRow("mixed") << (Item::List() << u1 << r1) << Scope() << true; QTest::newRow("single hrid") << (Item::List() << h1) << Scope({ Scope::HRID(-1, QStringLiteral("H1")), Scope::HRID(0) }) << false; QTest::newRow("single hrid 2") << (Item::List() << h2) << Scope({ Scope::HRID(-1, QStringLiteral("H2a")), Scope::HRID(-2, QStringLiteral("H2b")), Scope::HRID(0) }) << false; QTest::newRow("mixed hrid/rid") << (Item::List() << h1 << r1) << Scope(Scope::Rid, { QStringLiteral("H1"), QStringLiteral("A") }) << false; QTest::newRow("unterminated hrid") << (Item::List() << h3) << Scope(Scope::Rid, { QStringLiteral("H3a") }) << false; } void testItemSetToByteArray() { QFETCH(Item::List, items); QFETCH(Scope, result); QFETCH(bool, shouldThrow); bool didThrow = false; try { const Scope scope = ProtocolHelper::entitySetToScope(items); QCOMPARE(scope, result); } catch (const std::exception &e) { qDebug() << e.what(); didThrow = true; } QCOMPARE(didThrow, shouldThrow); } void testAncestorParsing_data() { QTest::addColumn>("input"); QTest::addColumn("parent"); QTest::newRow("top-level") << QVector { Protocol::Ancestor(0) } << Collection::root(); Protocol::Ancestor a1(42); a1.setRemoteId(QStringLiteral("net")); Collection c1; c1.setRemoteId(QStringLiteral("net")); c1.setId(42); c1.setParentCollection(Collection::root()); QTest::newRow("till's obscure folder") << QVector { a1, Protocol::Ancestor(0) } << c1; } void testAncestorParsing() { QFETCH(QVector, input); QFETCH(Collection, parent); Item i; ProtocolHelper::parseAncestors(input, &i); QCOMPARE(i.parentCollection().id(), parent.id()); QCOMPARE(i.parentCollection().remoteId(), parent.remoteId()); } void testCollectionParsing_data() { QTest::addColumn("input"); QTest::addColumn("collection"); Collection c1; c1.setId(2); c1.setRemoteId(QStringLiteral("r2")); c1.parentCollection().setId(1); c1.setName(QStringLiteral("n2")); { Protocol::FetchCollectionsResponse resp(2); resp.setParentId(1); resp.setRemoteId(QStringLiteral("r2")); resp.setName(QStringLiteral("n2")); QTest::newRow("no ancestors") << resp << c1; } { Protocol::FetchCollectionsResponse resp(3); resp.setParentId(2); resp.setRemoteId(QStringLiteral("r3")); resp.setAncestors({ Protocol::Ancestor(2, QStringLiteral("r2")), Protocol::Ancestor(1, QStringLiteral("r1")), Protocol::Ancestor(0) }); Collection c2; c2.setId(3); c2.setRemoteId(QStringLiteral("r3")); c2.parentCollection().setId(2); c2.parentCollection().setRemoteId(QStringLiteral("r2")); c2.parentCollection().parentCollection().setId(1); c2.parentCollection().parentCollection().setRemoteId(QStringLiteral("r1")); c2.parentCollection().parentCollection().setParentCollection(Collection::root()); QTest::newRow("ancestors") << resp << c2; } } void testCollectionParsing() { QFETCH(Protocol::FetchCollectionsResponse, input); QFETCH(Collection, collection); Collection parsedCollection = ProtocolHelper::parseCollection(input); QCOMPARE(parsedCollection.name(), collection.name()); while (collection.isValid() || parsedCollection.isValid()) { QCOMPARE(parsedCollection.id(), collection.id()); QCOMPARE(parsedCollection.remoteId(), collection.remoteId()); const Collection p1(parsedCollection.parentCollection()); const Collection p2(collection.parentCollection()); parsedCollection = p1; collection = p2; qDebug() << p1.isValid() << p2.isValid(); } } void testParentCollectionAfterCollectionParsing() { Protocol::FetchCollectionsResponse resp(111); resp.setParentId(222); resp.setRemoteId(QStringLiteral("A")); resp.setAncestors({ Protocol::Ancestor(222), Protocol::Ancestor(333), Protocol::Ancestor(0) }); Collection parsedCollection = ProtocolHelper::parseCollection(resp); QList ids; ids << 111 << 222 << 333 << 0; int i = 0; Collection col = parsedCollection; while (col.isValid()) { QCOMPARE(col.id(), ids[i++]); col = col.parentCollection(); } QCOMPARE(i, 4); } void testHRidToScope_data() { QTest::addColumn("collection"); QTest::addColumn("result"); QTest::newRow("empty") << Collection() << Scope(); { Scope scope; scope.setHRidChain({ Scope::HRID(0) }); QTest::newRow("root") << Collection::root() << scope; } Collection c; c.setId(1); c.setParentCollection(Collection::root()); c.setRemoteId(QStringLiteral("r1")); { Scope scope; scope.setHRidChain({ Scope::HRID(1, QStringLiteral("r1")), Scope::HRID(0) }); QTest::newRow("one level") << c << scope; } { Collection c2; c2.setId(2); c2.setParentCollection(c); c2.setRemoteId(QStringLiteral("r2")); Scope scope; scope.setHRidChain({ Scope::HRID(2, QStringLiteral("r2")), Scope::HRID(1, QStringLiteral("r1")), Scope::HRID(0) }); QTest::newRow("two level ok") << c2 << scope; } } void testHRidToScope() { QFETCH(Collection, collection); QFETCH(Scope, result); QCOMPARE(ProtocolHelper::hierarchicalRidToScope(collection), result); } void testItemFetchScopeToProtocol_data() { QTest::addColumn("scope"); QTest::addColumn("result"); { Protocol::ItemFetchScope fs; fs.setFetch(Protocol::ItemFetchScope::Flags | Protocol::ItemFetchScope::Size | Protocol::ItemFetchScope::RemoteID | Protocol::ItemFetchScope::RemoteRevision | Protocol::ItemFetchScope::MTime); QTest::newRow("empty") << ItemFetchScope() << fs; } { ItemFetchScope scope; scope.fetchAllAttributes(); scope.fetchFullPayload(); scope.setAncestorRetrieval(Akonadi::ItemFetchScope::All); scope.setIgnoreRetrievalErrors(true); Protocol::ItemFetchScope fs; fs.setFetch(Protocol::ItemFetchScope::FullPayload | Protocol::ItemFetchScope::AllAttributes | Protocol::ItemFetchScope::Flags | Protocol::ItemFetchScope::Size | Protocol::ItemFetchScope::RemoteID | Protocol::ItemFetchScope::RemoteRevision | Protocol::ItemFetchScope::MTime | Protocol::ItemFetchScope::IgnoreErrors); fs.setAncestorDepth(Protocol::ItemFetchScope::AllAncestors); QTest::newRow("full") << scope << fs; } { ItemFetchScope scope; scope.setFetchModificationTime(false); scope.setFetchRemoteIdentification(false); Protocol::ItemFetchScope fs; fs.setFetch(Protocol::ItemFetchScope::Flags | Protocol::ItemFetchScope::Size); QTest::newRow("minimal") << scope << fs; } } void testItemFetchScopeToProtocol() { QFETCH(ItemFetchScope, scope); QFETCH(Protocol::ItemFetchScope, result); QCOMPARE(ProtocolHelper::itemFetchScopeToProtocol(scope), result); } void testTagParsing_data() { QTest::addColumn("input"); QTest::addColumn("expected"); QTest::newRow("invalid") << Protocol::FetchTagsResponse(-1) << Tag(); Protocol::FetchTagsResponse response(15); response.setGid("TAG13GID"); response.setRemoteId("TAG13RID"); response.setParentId(-1); response.setType("PLAIN"); response.setAttributes({ { "TAGAttribute", "MyAttribute" } }); Tag tag(15); tag.setGid("TAG13GID"); tag.setRemoteId("TAG13RID"); tag.setType("PLAIN"); auto attr = AttributeFactory::createAttribute("TAGAttribute"); attr->deserialize("MyAttribute"); tag.addAttribute(attr); QTest::newRow("valid with invalid parent") << response << tag; response.setParentId(15); tag.setParent(Tag(15)); QTest::newRow("valid with valid parent") << response << tag; } void testTagParsing() { QFETCH(Protocol::FetchTagsResponse, input); QFETCH(Tag, expected); const Tag tag = ProtocolHelper::parseTagFetchResult(input); QCOMPARE(tag.id(), expected.id()); QCOMPARE(tag.gid(), expected.gid()); QCOMPARE(tag.remoteId(), expected.remoteId()); QCOMPARE(tag.type(), expected.type()); QCOMPARE(tag.parent(), expected.parent()); QCOMPARE(tag.attributes().size(), expected.attributes().size()); for (int i = 0; i < tag.attributes().size(); ++i) { Attribute *attr = tag.attributes().at(i); Attribute *expectedAttr = expected.attributes().at(i); QCOMPARE(attr->type(), expectedAttr->type()); QCOMPARE(attr->serialized(), expectedAttr->serialized()); } } }; QTEST_MAIN(ProtocolHelperTest) #include "protocolhelpertest.moc" diff --git a/autotests/libs/relationtest.cpp b/autotests/libs/relationtest.cpp index aa77b153e..e0b203943 100644 --- a/autotests/libs/relationtest.cpp +++ b/autotests/libs/relationtest.cpp @@ -1,178 +1,177 @@ /* Copyright (c) 2014 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include "test_utils.h" #include "control.h" #include "relationcreatejob.h" #include "relationfetchjob.h" #include "relationdeletejob.h" #include "tagmodifyjob.h" #include "resourceselectjob_p.h" #include "qtest_akonadi.h" #include "item.h" #include "itemcreatejob.h" #include "itemmodifyjob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "monitor.h" #include "attributefactory.h" using namespace Akonadi; class RelationTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testCreateFetch(); void testMonitor(); void testEqualRelation(); }; void RelationTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); AkonadiTest::setAllResourcesOffline(); qRegisterMetaType(); qRegisterMetaType >(); qRegisterMetaType(); } void RelationTest::testCreateFetch() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3{AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))}; Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } Item item2; { item2.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item2, res3, this); AKVERIFYEXEC(append); item2 = append->item(); } Relation rel(Relation::GENERIC, item1, item2); RelationCreateJob *createjob = new RelationCreateJob(rel, this); AKVERIFYEXEC(createjob); //Test fetch & create { RelationFetchJob *fetchJob = new RelationFetchJob(QVector(), this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->relations().size(), 1); QCOMPARE(fetchJob->relations().first().type(), QByteArray(Relation::GENERIC)); } //Test item fetch { ItemFetchJob *fetchJob = new ItemFetchJob(item1); fetchJob->fetchScope().setFetchRelations(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().relations().size(), 1); } { ItemFetchJob *fetchJob = new ItemFetchJob(item2); fetchJob->fetchScope().setFetchRelations(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().relations().size(), 1); } //Test delete { RelationDeleteJob *deleteJob = new RelationDeleteJob(rel, this); AKVERIFYEXEC(deleteJob); RelationFetchJob *fetchJob = new RelationFetchJob(QVector(), this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->relations().size(), 0); } } void RelationTest::testMonitor() { Akonadi::Monitor monitor; monitor.setTypeMonitored(Akonadi::Monitor::Relations); QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3{AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))}; Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } Item item2; { item2.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item2, res3, this); AKVERIFYEXEC(append); item2 = append->item(); } Relation rel(Relation::GENERIC, item1, item2); { QSignalSpy addedSpy(&monitor, &Monitor::relationAdded); RelationCreateJob *createjob = new RelationCreateJob(rel, this); AKVERIFYEXEC(createjob); //We usually pick up signals from the previous tests as well (due to server-side notification caching) QTRY_VERIFY(addedSpy.count() >= 1); QTRY_COMPARE(addedSpy.last().first().value(), rel); } { QSignalSpy removedSpy(&monitor, &Monitor::relationRemoved); QVERIFY(removedSpy.isValid()); RelationDeleteJob *deleteJob = new RelationDeleteJob(rel, this); AKVERIFYEXEC(deleteJob); QTRY_VERIFY(removedSpy.count() >= 1); QTRY_COMPARE(removedSpy.last().first().value(), rel); } } void RelationTest::testEqualRelation() { Relation r1; Item it1(45); Item it2(46); r1.setLeft(it1); r1.setRight(it2); r1.setRemoteId(QByteArrayLiteral("foo")); r1.setType(QByteArrayLiteral("foo1")); Relation r2 = r1; QCOMPARE(r1, r2); } QTEST_AKONADIMAIN(RelationTest) #include "relationtest.moc" diff --git a/autotests/libs/servermanagertest.cpp b/autotests/libs/servermanagertest.cpp index df43a6e12..ea1f662e0 100644 --- a/autotests/libs/servermanagertest.cpp +++ b/autotests/libs/servermanagertest.cpp @@ -1,94 +1,93 @@ /* Copyright (c) 2008 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "control.h" #include "servermanager.h" #include "qtest_akonadi.h" -#include "test_utils.h" #include using namespace Akonadi; class ServerManagerTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); QVERIFY(Control::start()); trackAkonadiProcess(false); } void cleanupTestCase() { trackAkonadiProcess(true); } void testStartStop() { QSignalSpy startSpy(ServerManager::self(), SIGNAL(started())); QVERIFY(startSpy.isValid()); QSignalSpy stopSpy(ServerManager::self(), SIGNAL(stopped())); QVERIFY(stopSpy.isValid()); QVERIFY(ServerManager::isRunning()); QVERIFY(Control::start()); QVERIFY(startSpy.isEmpty()); QVERIFY(stopSpy.isEmpty()); { QSignalSpy spy(ServerManager::self(), SIGNAL(stopped())); QVERIFY(ServerManager::stop()); QTRY_VERIFY(spy.count() >= 1); } QVERIFY(!ServerManager::isRunning()); QVERIFY(startSpy.isEmpty()); QCOMPARE(stopSpy.count(), 1); QVERIFY(!ServerManager::stop()); { QSignalSpy spy(ServerManager::self(), SIGNAL(started())); QVERIFY(ServerManager::start()); QTRY_VERIFY(spy.count() >= 1); } QVERIFY(ServerManager::isRunning()); QCOMPARE(startSpy.count(), 1); QCOMPARE(stopSpy.count(), 1); } void testRestart() { QVERIFY(ServerManager::isRunning()); QSignalSpy startSpy(ServerManager::self(), SIGNAL(started())); QVERIFY(startSpy.isValid()); QVERIFY(Control::restart()); QVERIFY(ServerManager::isRunning()); QCOMPARE(startSpy.count(), 1); } }; QTEST_AKONADIMAIN(ServerManagerTest) #include "servermanagertest.moc" diff --git a/autotests/libs/subscriptiontest.cpp b/autotests/libs/subscriptiontest.cpp index 64012713f..81a4ee1c5 100644 --- a/autotests/libs/subscriptiontest.cpp +++ b/autotests/libs/subscriptiontest.cpp @@ -1,93 +1,92 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" #include "control.h" #include "collection.h" #include "collectionfetchjob.h" #include "collectionfetchscope.h" #include "subscriptionjob_p.h" #include "qtest_akonadi.h" #include using namespace Akonadi; class SubscriptionTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); } void testSubscribe() { Collection::List l; - l << Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + l << Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/foo2"))); QVERIFY(l.first().isValid()); SubscriptionJob *sjob = new SubscriptionJob(this); sjob->unsubscribe(l); AKVERIFYEXEC(sjob); - const Collection res2Col = Collection(collectionIdFromPath(QStringLiteral("res2"))); + const Collection res2Col = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2"))); QVERIFY(res2Col.isValid()); CollectionFetchJob *ljob = new CollectionFetchJob(res2Col, CollectionFetchJob::FirstLevel, this); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 1); ljob = new CollectionFetchJob(res2Col, CollectionFetchJob::FirstLevel, this); ljob->fetchScope().setListFilter(CollectionFetchScope::NoFilter); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 2); sjob = new SubscriptionJob(this); sjob->subscribe(l); AKVERIFYEXEC(sjob); ljob = new CollectionFetchJob(res2Col, CollectionFetchJob::FirstLevel, this); AKVERIFYEXEC(ljob); QCOMPARE(ljob->collections().count(), 2); } void testEmptySubscribe() { Collection::List l; SubscriptionJob *sjob = new SubscriptionJob(this); AKVERIFYEXEC(sjob); } void testInvalidSubscribe() { Collection::List l; l << Collection(1); SubscriptionJob *sjob = new SubscriptionJob(this); sjob->subscribe(l); l << Collection(INT_MAX); sjob->unsubscribe(l); QVERIFY(!sjob->exec()); } }; QTEST_AKONADIMAIN(SubscriptionTest) #include "subscriptiontest.moc" diff --git a/autotests/libs/tagsynctest.cpp b/autotests/libs/tagsynctest.cpp index f394fd321..6e499bf01 100644 --- a/autotests/libs/tagsynctest.cpp +++ b/autotests/libs/tagsynctest.cpp @@ -1,267 +1,265 @@ /* Copyright (c) 2014 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "test_utils.h" - #include "agentmanager.h" #include "agentinstance.h" #include "control.h" #include "tagfetchjob.h" #include "tagdeletejob.h" #include "tagcreatejob.h" #include "tag.h" #include "tagsync.h" #include "tagfetchscope.h" #include "resourceselectjob_p.h" #include "itemcreatejob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "qtest_akonadi.h" #include using namespace Akonadi; class TagSyncTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AkonadiTest::setAllResourcesOffline(); cleanTags(); } Tag::List getTags() { TagFetchJob *fetchJob = new TagFetchJob(); fetchJob->fetchScope().setFetchRemoteId(true); bool ret = fetchJob->exec(); Q_ASSERT(ret); return fetchJob->tags(); } Tag::List getTagsWithRid() { Tag::List tags; Q_FOREACH (const Tag &t, getTags()) { if (!t.remoteId().isEmpty()) { tags << t; qDebug() << t.remoteId(); } } return tags; } void cleanTags() { Q_FOREACH (const Tag &t, getTags()) { TagDeleteJob *job = new TagDeleteJob(t); bool ret = job->exec(); Q_ASSERT(ret); } } void newTag() { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); Tag::List remoteTags; Tag tag1(QStringLiteral("tag1")); tag1.setRemoteId("rid1"); remoteTags << tag1; TagSync *syncer = new TagSync(this); syncer->setFullTagList(remoteTags); syncer->setTagMembers(QHash()); AKVERIFYEXEC(syncer); Tag::List resultTags = getTags(); QCOMPARE(resultTags.count(), remoteTags.count()); QCOMPARE(resultTags, remoteTags); cleanTags(); } void newTagWithItems() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_2")); AKVERIFYEXEC(select); Tag::List remoteTags; Tag tag1(QStringLiteral("tag1")); tag1.setRemoteId("rid1"); remoteTags << tag1; Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); item1.setRemoteId(QStringLiteral("item1")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } QHash tagMembers; tagMembers.insert(QString::fromLatin1(tag1.remoteId()), { item1 }); TagSync *syncer = new TagSync(this); syncer->setFullTagList(remoteTags); syncer->setTagMembers(tagMembers); AKVERIFYEXEC(syncer); Tag::List resultTags = getTags(); QCOMPARE(resultTags.count(), remoteTags.count()); QCOMPARE(resultTags, remoteTags); //We need the id of the fetch tag1 = resultTags.first(); ItemFetchJob *fetchJob = new ItemFetchJob(tag1); fetchJob->fetchScope().setFetchTags(true); fetchJob->fetchScope().tagFetchScope().setFetchRemoteId(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().count(), tagMembers.value(QString::fromLatin1(tag1.remoteId())).count()); QCOMPARE(fetchJob->items(), tagMembers.value(QString::fromLatin1(tag1.remoteId()))); cleanTags(); } void existingTag() { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); Tag tag1(QStringLiteral("tag1")); tag1.setRemoteId("rid1"); TagCreateJob *createJob = new TagCreateJob(tag1, this); AKVERIFYEXEC(createJob); Tag::List remoteTags; remoteTags << tag1; TagSync *syncer = new TagSync(this); syncer->setFullTagList(remoteTags); syncer->setTagMembers(QHash()); AKVERIFYEXEC(syncer); Tag::List resultTags = getTags(); QCOMPARE(resultTags.count(), remoteTags.count()); QCOMPARE(resultTags, remoteTags); cleanTags(); } void existingTagWithItems() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_2")); AKVERIFYEXEC(select); Tag tag1(QStringLiteral("tag1")); tag1.setRemoteId("rid1"); TagCreateJob *createJob = new TagCreateJob(tag1, this); AKVERIFYEXEC(createJob); Tag::List remoteTags; remoteTags << tag1; Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); item1.setRemoteId(QStringLiteral("item1")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } Item item2; { item2.setMimeType(QStringLiteral("application/octet-stream")); item2.setRemoteId(QStringLiteral("item2")); item2.setTag(tag1); ItemCreateJob *append = new ItemCreateJob(item2, res3, this); AKVERIFYEXEC(append); item2 = append->item(); } QHash tagMembers; tagMembers.insert(QString::fromLatin1(tag1.remoteId()), Item::List() << item1); TagSync *syncer = new TagSync(this); syncer->setFullTagList(remoteTags); syncer->setTagMembers(tagMembers); AKVERIFYEXEC(syncer); Tag::List resultTags = getTags(); QCOMPARE(resultTags.count(), remoteTags.count()); QCOMPARE(resultTags, remoteTags); { ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().count(), 1); } { ItemFetchJob *fetchJob = new ItemFetchJob(item2, this); fetchJob->fetchScope().setFetchTags(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().count(), 0); } cleanTags(); } void removeTag() { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); Tag tag1(QStringLiteral("tag1")); tag1.setRemoteId("rid1"); TagCreateJob *createJob = new TagCreateJob(tag1, this); AKVERIFYEXEC(createJob); Tag::List remoteTags; TagSync *syncer = new TagSync(this); syncer->setFullTagList(remoteTags); syncer->setTagMembers(QHash()); AKVERIFYEXEC(syncer); Tag::List resultTags = getTagsWithRid(); QCOMPARE(resultTags.count(), remoteTags.count()); QCOMPARE(resultTags, remoteTags); cleanTags(); } }; QTEST_AKONADIMAIN(TagSyncTest) #include "tagsynctest.moc" diff --git a/autotests/libs/tagtest.cpp b/autotests/libs/tagtest.cpp index 53e789990..013d49b0d 100644 --- a/autotests/libs/tagtest.cpp +++ b/autotests/libs/tagtest.cpp @@ -1,940 +1,939 @@ /* Copyright (c) 2014 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include "test_utils.h" #include "control.h" #include "tagcreatejob.h" #include "tagfetchjob.h" #include "tagdeletejob.h" #include "tagattribute.h" #include "tagfetchscope.h" #include "tagmodifyjob.h" #include "resourceselectjob_p.h" #include "qtest_akonadi.h" #include "item.h" #include "itemcreatejob.h" #include "itemmodifyjob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "monitor.h" #include "attributefactory.h" using namespace Akonadi; class TagTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testTag(); void testCreateFetch(); void testRID(); void testDelete(); void testDeleteRIDIsolation(); void testModify(); void testModifyFromResource(); void testCreateMerge(); void testAttributes(); void testTagItem(); void testCreateItem(); void testRIDIsolation(); void testFetchTagIdWithItem(); void testFetchFullTagWithItem(); void testModifyItemWithTagByGID(); void testModifyItemWithTagByRID(); void testMonitor(); void testTagAttributeConfusionBug(); void testFetchItemsByTag(); void tagModifyJobShouldOnlySendModifiedAttributes(); }; void TagTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); AkonadiTest::setAllResourcesOffline(); AttributeFactory::registerAttribute(); qRegisterMetaType(); qRegisterMetaType >(); qRegisterMetaType(); // Delete the default Knut tag - it's interfering with this test TagFetchJob *fetchJob = new TagFetchJob(this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); AKVERIFYEXEC(deleteJob); } void TagTest::testTag() { Tag tag1; Tag tag2; // Invalid tags are equal QVERIFY(tag1 == tag2); // Invalid tags with different GIDs are not equal tag1.setGid("GID1"); QVERIFY(tag1 != tag2); tag2.setGid("GID2"); QVERIFY(tag1 != tag2); // Invalid tags with equal GIDs are equal tag1.setGid("GID2"); QVERIFY(tag1 == tag2); // Valid tags with different IDs are not equal tag1 = Tag(1); tag2 = Tag(2); QVERIFY(tag1 != tag2); // Valid tags with different IDs and equal GIDs are still not equal tag1.setGid("GID1"); tag2.setGid("GID1"); QVERIFY(tag1 != tag2); // Valid tags with equal ID are equal regardless of GIDs tag2 = Tag(1); tag2.setGid("GID2"); QVERIFY(tag1 == tag2); } void TagTest::testCreateFetch() { Tag tag; tag.setGid("gid"); tag.setType("mytype"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); { TagFetchJob *fetchJob = new TagFetchJob(this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); AKVERIFYEXEC(deleteJob); } { TagFetchJob *fetchJob = new TagFetchJob(this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 0); } } void TagTest::testRID() { { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); } Tag tag; tag.setGid("gid"); tag.setType("mytype"); tag.setRemoteId("rid"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); { TagFetchJob *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().setFetchRemoteId(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid")); TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); AKVERIFYEXEC(deleteJob); } { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); AKVERIFYEXEC(select); } } void TagTest::testRIDIsolation() { { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); } Tag tag; tag.setGid("gid"); tag.setType("mytype"); tag.setRemoteId("rid_0"); TagCreateJob *createJob = new TagCreateJob(tag, this); AKVERIFYEXEC(createJob); QVERIFY(createJob->tag().isValid()); qint64 tagId; { TagFetchJob *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().setFetchRemoteId(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().count(), 1); QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid_0")); tagId = fetchJob->tags().first().id(); } { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_1")); AKVERIFYEXEC(select); } tag.setRemoteId("rid_1"); createJob = new TagCreateJob(tag, this); createJob->setMergeIfExisting(true); AKVERIFYEXEC(createJob); QVERIFY(createJob->tag().isValid()); { TagFetchJob *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().setFetchRemoteId(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().count(), 1); QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid_1")); QCOMPARE(fetchJob->tags().first().id(), tagId); } TagDeleteJob *deleteJob = new TagDeleteJob(Tag(tagId), this); AKVERIFYEXEC(deleteJob); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); AKVERIFYEXEC(select); } } void TagTest::testDelete() { Akonadi::Monitor monitor; monitor.setTypeMonitored(Monitor::Tags); QSignalSpy spy(&monitor, &Monitor::tagRemoved); Tag tag1; { tag1.setGid("tag1"); TagCreateJob *createjob = new TagCreateJob(tag1, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag1 = createjob->tag(); } Tag tag2; { tag2.setGid("tag2"); TagCreateJob *createjob = new TagCreateJob(tag2, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag2 = createjob->tag(); } { TagDeleteJob *deleteJob = new TagDeleteJob(tag1, this); AKVERIFYEXEC(deleteJob); } { TagFetchJob *fetchJob = new TagFetchJob(this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QCOMPARE(fetchJob->tags().first().gid(), tag2.gid()); } { TagDeleteJob *deleteJob = new TagDeleteJob(tag2, this); AKVERIFYEXEC(deleteJob); } // Collect Remove notification, so that they don't interfere with testDeleteRIDIsolation QTRY_VERIFY(!spy.isEmpty()); } void TagTest::testDeleteRIDIsolation() { Tag tag; tag.setGid("gid"); tag.setType("mytype"); tag.setRemoteId("rid_0"); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); TagCreateJob *createJob = new TagCreateJob(tag, this); AKVERIFYEXEC(createJob); QVERIFY(createJob->tag().isValid()); tag.setId(createJob->tag().id()); } tag.setRemoteId("rid_1"); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_1")); AKVERIFYEXEC(select); TagCreateJob *createJob = new TagCreateJob(tag, this); createJob->setMergeIfExisting(true); AKVERIFYEXEC(createJob); QVERIFY(createJob->tag().isValid()); } - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy signalSpy(monitor.get(), &Monitor::tagRemoved); TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); // Other tests notifications might interfere due to notification compression on server QTRY_VERIFY(signalSpy.count() >= 1); Tag removedTag; while (!signalSpy.isEmpty()) { const Tag t = signalSpy.takeFirst().takeFirst().value(); if (t.id() == tag.id()) { removedTag = t; break; } } QVERIFY(removedTag.isValid()); QVERIFY(removedTag.remoteId().isEmpty()); { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral(""), this); AKVERIFYEXEC(select); } } void TagTest::testModify() { Tag tag; { tag.setGid("gid"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag = createjob->tag(); } //We can add an attribute { Akonadi::TagAttribute *attr = tag.attribute(Tag::AddIfMissing); attr->setDisplayName(QStringLiteral("display name")); tag.setParent(Tag(0)); tag.setType("mytype"); TagModifyJob *modJob = new TagModifyJob(tag, this); AKVERIFYEXEC(modJob); TagFetchJob *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QVERIFY(fetchJob->tags().first().hasAttribute()); } //We can update an attribute { Akonadi::TagAttribute *attr = tag.attribute(Tag::AddIfMissing); attr->setDisplayName(QStringLiteral("display name2")); TagModifyJob *modJob = new TagModifyJob(tag, this); AKVERIFYEXEC(modJob); TagFetchJob *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QVERIFY(fetchJob->tags().first().hasAttribute()); QCOMPARE(fetchJob->tags().first().attribute()->displayName(), attr->displayName()); } //We can clear an attribute { tag.removeAttribute(); TagModifyJob *modJob = new TagModifyJob(tag, this); AKVERIFYEXEC(modJob); TagFetchJob *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QVERIFY(!fetchJob->tags().first().hasAttribute()); } TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::testModifyFromResource() { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); Tag tag; { tag.setGid("gid"); tag.setRemoteId("rid"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag = createjob->tag(); } { tag.setRemoteId(QByteArray("")); TagModifyJob *modJob = new TagModifyJob(tag, this); AKVERIFYEXEC(modJob); // The tag is removed on the server, because we just removed the last // RemoteID TagFetchJob *fetchJob = new TagFetchJob(this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 0); } } void TagTest::testCreateMerge() { Tag tag; { tag.setGid("gid"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag = createjob->tag(); } { Tag tag2; tag2.setGid("gid"); TagCreateJob *createjob = new TagCreateJob(tag2, this); createjob->setMergeIfExisting(true); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); QCOMPARE(createjob->tag().id(), tag.id()); } TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::testAttributes() { Tag tag; { tag.setGid("gid2"); TagAttribute *attr = tag.attribute(Tag::AddIfMissing); attr->setDisplayName(QStringLiteral("name")); attr->setInToolbar(true); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag = createjob->tag(); { TagFetchJob *fetchJob = new TagFetchJob(createjob->tag(), this); fetchJob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QVERIFY(fetchJob->tags().first().hasAttribute()); //we need to clone because the returned attribute is just a reference and destroyed on the next line //FIXME we should find a better solution for this (like returning a smart pointer or value object) QScopedPointer tagAttr(fetchJob->tags().first().attribute()->clone()); QVERIFY(tagAttr); QCOMPARE(tagAttr->displayName(), QStringLiteral("name")); QCOMPARE(tagAttr->inToolbar(), true); } } //Try fetching multiple items Tag tag2; { tag2.setGid("gid22"); TagAttribute *attr = tag.attribute(Tag::AddIfMissing)->clone(); attr->setDisplayName(QStringLiteral("name2")); attr->setInToolbar(true); tag2.addAttribute(attr); TagCreateJob *createjob = new TagCreateJob(tag2, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); tag2 = createjob->tag(); { TagFetchJob *fetchJob = new TagFetchJob(Tag::List() << tag << tag2, this); fetchJob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 2); QVERIFY(fetchJob->tags().at(0).hasAttribute()); QVERIFY(fetchJob->tags().at(1).hasAttribute()); } } TagDeleteJob *deleteJob = new TagDeleteJob(Tag::List() << tag << tag2, this); AKVERIFYEXEC(deleteJob); } void TagTest::testTagItem() { Akonadi::Monitor monitor; monitor.itemFetchScope().setFetchTags(true); monitor.setAllMonitored(true); QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); Tag tag; { TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); AKVERIFYEXEC(createjob); tag = createjob->tag(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } item1.setTag(tag); QSignalSpy tagsSpy(&monitor, &Monitor::itemsTagsChanged); ItemModifyJob *modJob = new ItemModifyJob(item1, this); AKVERIFYEXEC(modJob); QTRY_VERIFY(tagsSpy.count() >= 1); QTRY_COMPARE(tagsSpy.last().first().value().first().id(), item1.id()); QTRY_COMPARE(tagsSpy.last().at(1).value< QSet >().size(), 1); //1 added tag ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().size(), 1); TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::testCreateItem() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); Tag tag; { TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); AKVERIFYEXEC(createjob); tag = createjob->tag(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); item1.setTag(tag); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().size(), 1); TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::testFetchTagIdWithItem() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); Tag tag; { TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); AKVERIFYEXEC(createjob); tag = createjob->tag(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); item1.setTag(tag); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); fetchJob->fetchScope().tagFetchScope().setFetchIdOnly(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().size(), 1); Tag t = fetchJob->items().first().tags().first(); QCOMPARE(t.id(), tag.id()); QVERIFY(t.gid().isEmpty()); TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::testFetchFullTagWithItem() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); Tag tag; { TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); AKVERIFYEXEC(createjob); tag = createjob->tag(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); //FIXME This should also be possible with create, but isn't item1.setTag(tag); } ItemModifyJob *modJob = new ItemModifyJob(item1, this); AKVERIFYEXEC(modJob); ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); fetchJob->fetchScope().tagFetchScope().setFetchIdOnly(false); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().size(), 1); Tag t = fetchJob->items().first().tags().first(); QCOMPARE(t, tag); QVERIFY(!t.gid().isEmpty()); TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::testModifyItemWithTagByGID() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); { Tag tag; tag.setGid("gid2"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } Tag tag; tag.setGid("gid2"); item1.setTag(tag); ItemModifyJob *modJob = new ItemModifyJob(item1, this); AKVERIFYEXEC(modJob); ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().size(), 1); TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->items().first().tags().first(), this); AKVERIFYEXEC(deleteJob); } void TagTest::testModifyItemWithTagByRID() { { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); AKVERIFYEXEC(select); } - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); Tag tag3; { tag3.setGid("gid3"); tag3.setRemoteId("rid3"); TagCreateJob *createjob = new TagCreateJob(tag3, this); AKVERIFYEXEC(createjob); tag3 = createjob->tag(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); } Tag tag; tag.setRemoteId("rid2"); item1.setTag(tag); ItemModifyJob *modJob = new ItemModifyJob(item1, this); AKVERIFYEXEC(modJob); ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); fetchJob->fetchScope().setFetchTags(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().first().tags().size(), 1); { TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->items().first().tags().first(), this); AKVERIFYEXEC(deleteJob); } { TagDeleteJob *deleteJob = new TagDeleteJob(tag3, this); AKVERIFYEXEC(deleteJob); } { ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); AKVERIFYEXEC(select); } } void TagTest::testMonitor() { Akonadi::Monitor monitor; monitor.setTypeMonitored(Akonadi::Monitor::Tags); monitor.tagFetchScope().fetchAttribute(); QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); Akonadi::Tag createdTag; { QSignalSpy addedSpy(&monitor, &Monitor::tagAdded); QVERIFY(addedSpy.isValid()); Tag tag; tag.setGid("gid2"); tag.setName(QStringLiteral("name2")); tag.setType("type2"); TagCreateJob *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); createdTag = createjob->tag(); QCOMPARE(createdTag.type(), tag.type()); QCOMPARE(createdTag.name(), tag.name()); QCOMPARE(createdTag.gid(), tag.gid()); //We usually pick up signals from the previous tests as well (due to server-side notification caching) QTRY_VERIFY(addedSpy.count() >= 1); QTRY_COMPARE(addedSpy.last().first().value().id(), createdTag.id()); const Akonadi::Tag notifiedTag = addedSpy.last().first().value(); QCOMPARE(notifiedTag.type(), createdTag.type()); QCOMPARE(notifiedTag.gid(), createdTag.gid()); QVERIFY(notifiedTag.hasAttribute()); QCOMPARE(notifiedTag.name(), createdTag.name()); // requires the TagAttribute } { QSignalSpy modifiedSpy(&monitor, &Monitor::tagChanged); QVERIFY(modifiedSpy.isValid()); createdTag.setName(QStringLiteral("name3")); TagModifyJob *modJob = new TagModifyJob(createdTag, this); AKVERIFYEXEC(modJob); //We usually pick up signals from the previous tests as well (due to server-side notification caching) QTRY_VERIFY(modifiedSpy.count() >= 1); QTRY_COMPARE(modifiedSpy.last().first().value().id(), createdTag.id()); const Akonadi::Tag notifiedTag = modifiedSpy.last().first().value(); QCOMPARE(notifiedTag.type(), createdTag.type()); QCOMPARE(notifiedTag.gid(), createdTag.gid()); QVERIFY(notifiedTag.hasAttribute()); QCOMPARE(notifiedTag.name(), createdTag.name()); // requires the TagAttribute } { QSignalSpy removedSpy(&monitor, &Monitor::tagRemoved); QVERIFY(removedSpy.isValid()); TagDeleteJob *deletejob = new TagDeleteJob(createdTag, this); AKVERIFYEXEC(deletejob); QTRY_VERIFY(removedSpy.count() >= 1); QTRY_COMPARE(removedSpy.last().first().value().id(), createdTag.id()); const Akonadi::Tag notifiedTag = removedSpy.last().first().value(); QCOMPARE(notifiedTag.type(), createdTag.type()); QCOMPARE(notifiedTag.gid(), createdTag.gid()); QVERIFY(notifiedTag.hasAttribute()); QCOMPARE(notifiedTag.name(), createdTag.name()); // requires the TagAttribute } } void TagTest::testTagAttributeConfusionBug() { // Create two tags Tag firstTag; { firstTag.setGid("gid"); firstTag.setName(QStringLiteral("display name")); TagCreateJob *createjob = new TagCreateJob(firstTag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); firstTag = createjob->tag(); } Tag secondTag; { secondTag.setGid("AnotherGID"); secondTag.setName(QStringLiteral("another name")); TagCreateJob *createjob = new TagCreateJob(secondTag, this); AKVERIFYEXEC(createjob); QVERIFY(createjob->tag().isValid()); secondTag = createjob->tag(); } Akonadi::Monitor monitor; monitor.setTypeMonitored(Akonadi::Monitor::Tags); QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); const QList firstTagIdList{ firstTag.id() }; // Modify attribute on the first tag // and check the notification { QSignalSpy modifiedSpy(&monitor, &Akonadi::Monitor::tagChanged); firstTag.setName(QStringLiteral("renamed")); TagModifyJob *modJob = new TagModifyJob(firstTag, this); AKVERIFYEXEC(modJob); TagFetchJob *fetchJob = new TagFetchJob(firstTagIdList, this); QVERIFY(fetchJob->fetchScope().fetchAllAttributes()); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); QCOMPARE(fetchJob->tags().first().name(), firstTag.name()); QTRY_VERIFY(modifiedSpy.count() >= 1); QTRY_COMPARE(modifiedSpy.last().first().value().id(), firstTag.id()); const Akonadi::Tag notifiedTag = modifiedSpy.last().first().value(); QCOMPARE(notifiedTag.name(), firstTag.name()); } // Cleanup TagDeleteJob *deleteJob = new TagDeleteJob(firstTag, this); AKVERIFYEXEC(deleteJob); TagDeleteJob *anotherDeleteJob = new TagDeleteJob(secondTag, this); AKVERIFYEXEC(anotherDeleteJob); } void TagTest::testFetchItemsByTag() { - const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); Tag tag; { TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); AKVERIFYEXEC(createjob); tag = createjob->tag(); } Item item1; { item1.setMimeType(QStringLiteral("application/octet-stream")); ItemCreateJob *append = new ItemCreateJob(item1, res3, this); AKVERIFYEXEC(append); item1 = append->item(); //FIXME This should also be possible with create, but isn't item1.setTag(tag); } ItemModifyJob *modJob = new ItemModifyJob(item1, this); AKVERIFYEXEC(modJob); ItemFetchJob *fetchJob = new ItemFetchJob(tag, this); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->items().size(), 1); Item i = fetchJob->items().first(); QCOMPARE(i, item1); TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); AKVERIFYEXEC(deleteJob); } void TagTest::tagModifyJobShouldOnlySendModifiedAttributes() { // Given a tag with an attribute Tag tag(QStringLiteral("tagWithAttr")); auto *attr = new Akonadi::TagAttribute; attr->setDisplayName(QStringLiteral("display name")); tag.addAttribute(attr); { auto *createjob = new TagCreateJob(tag, this); AKVERIFYEXEC(createjob); tag = createjob->tag(); } // When one job modifies this attribute, and another one does an unrelated modify job Tag attrModTag(tag.id()); Akonadi::TagAttribute *modAttr = attrModTag.attribute(Tag::AddIfMissing); modAttr->setDisplayName(QStringLiteral("modified")); TagModifyJob *attrModJob = new TagModifyJob(attrModTag, this); AKVERIFYEXEC(attrModJob); tag.setType(Tag::GENERIC); // this job shouldn't send the old attribute again auto *modJob = new TagModifyJob(tag, this); AKVERIFYEXEC(modJob); // Then the tag should have both the modified attribute and the modified type { auto *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().fetchAttribute(); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); const Tag fetchedTag = fetchJob->tags().at(0); QVERIFY(fetchedTag.hasAttribute()); QCOMPARE(fetchedTag.attribute()->displayName(), QStringLiteral("modified")); QCOMPARE(fetchedTag.type(), Tag::GENERIC); } // And when adding a new attribute next to the old one auto *attr2 = AttributeFactory::createAttribute("SecondType"); tag.addAttribute(attr2); // this job shouldn't send the old attribute again auto *modJob2 = new TagModifyJob(tag, this); AKVERIFYEXEC(modJob2); // Then the tag should have the modified attribute and the second one { auto *fetchJob = new TagFetchJob(this); fetchJob->fetchScope().setFetchAllAttributes(true); AKVERIFYEXEC(fetchJob); QCOMPARE(fetchJob->tags().size(), 1); const Tag fetchedTag = fetchJob->tags().at(0); QVERIFY(fetchedTag.hasAttribute()); QCOMPARE(fetchedTag.attribute()->displayName(), QStringLiteral("modified")); QCOMPARE(fetchedTag.type(), Tag::GENERIC); QVERIFY(fetchedTag.attribute("SecondType")); } } #include "tagtest.moc" QTEST_AKONADIMAIN(TagTest) diff --git a/autotests/libs/test_utils.h b/autotests/libs/test_utils.h deleted file mode 100644 index 576ab7ec2..000000000 --- a/autotests/libs/test_utils.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright (c) 2009 Volker Krause - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef AKONADI_TEST_UTILS_H -#define AKONADI_TEST_UTILS_H - -#include "collectionpathresolver.h" -#include "servermanager.h" -#include "qtest_akonadi.h" -#include "monitor.h" -#include "collectionfetchscope.h" -#include "itemfetchscope.h" - -#include -#include -#include - -qint64 collectionIdFromPath(const QString &path) -{ - Akonadi::CollectionPathResolver *resolver = new Akonadi::CollectionPathResolver(path); - bool success = resolver->exec(); - if (!success) { - qDebug() << "path resolution for " << path << " failed: " << resolver->errorText(); - return -1; - } - qint64 id = resolver->collection(); - return id; -} - -QString testrunnerServiceName() -{ - const QString pid = QString::fromLocal8Bit(qgetenv("AKONADI_TESTRUNNER_PID")); - Q_ASSERT(!pid.isEmpty()); - return QStringLiteral("org.kde.Akonadi.Testrunner-") + pid; -} - -bool restartAkonadiServer() -{ - QDBusInterface testrunnerIface(testrunnerServiceName(), - QStringLiteral("/"), - QStringLiteral("org.kde.Akonadi.Testrunner"), - QDBusConnection::sessionBus()); - if (!testrunnerIface.isValid()) { - qWarning() << "Unable to get a dbus interface to the testrunner!"; - } - - QDBusReply reply = testrunnerIface.call(QStringLiteral("restartAkonadiServer")); - if (!reply.isValid()) { - qWarning() << reply.error(); - return false; - } else if (Akonadi::ServerManager::isRunning()) { - return true; - } else { - bool ok = false; - [&]() { - QSignalSpy spy(Akonadi::ServerManager::self(), &Akonadi::ServerManager::started); - QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 10000); - ok = true; - }(); - return ok; - } -} - -bool trackAkonadiProcess(bool track) -{ - QDBusInterface testrunnerIface(testrunnerServiceName(), - QStringLiteral("/"), - QStringLiteral("org.kde.Akonadi.Testrunner"), - QDBusConnection::sessionBus()); - if (!testrunnerIface.isValid()) { - qWarning() << "Unable to get a dbus interface to the testrunner!"; - } - - QDBusReply reply = testrunnerIface.call(QStringLiteral("trackAkonadiProcess"), track); - if (!reply.isValid()) { - qWarning() << reply.error(); - return false; - } else { - return true; - } -} - -std::unique_ptr getTestMonitor() -{ - auto m = new Akonadi::Monitor(); - m->fetchCollection(true); - m->setCollectionMonitored(Akonadi::Collection::root(), true); - m->setAllMonitored(true); - auto &itemFS = m->itemFetchScope(); - itemFS.setAncestorRetrieval(Akonadi::ItemFetchScope::All); - auto &colFS = m->collectionFetchScope(); - colFS.setAncestorRetrieval(Akonadi::CollectionFetchScope::All); - - QSignalSpy readySpy(m, &Akonadi::Monitor::monitorReady); - readySpy.wait(); - - return std::unique_ptr(m); -} - -#endif diff --git a/autotests/widgets/subscriptiondialogtest.cpp b/autotests/widgets/subscriptiondialogtest.cpp index a823e4b95..dcdf4024e 100644 --- a/autotests/widgets/subscriptiondialogtest.cpp +++ b/autotests/widgets/subscriptiondialogtest.cpp @@ -1,269 +1,267 @@ /* * Copyright 2020 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "qtest_akonadi.h" -#include -#include + #include #include -#include "../libs/test_utils.h" #include "subscriptiondialog.h" #include "subscriptionmodel_p.h" #include "subscriptionjob_p.h" #include #include #include #include #include #include #include #include #include #include using namespace Akonadi; class SubscriptionDialogTest: public QObject { Q_OBJECT struct TestSetup { enum { defaultCollectionCount = 7 }; TestSetup() { widget = std::make_unique(QStringList{ Collection::mimeType(), QStringLiteral("application/octet-stream") }); widget->setAttribute(Qt::WA_DeleteOnClose, false); widget->show(); model = widget->findChild(); QVERIFY(model); QSignalSpy modelLoadedSpy(model, &SubscriptionModel::modelLoaded); buttonBox = widget->findChild(); QVERIFY(buttonBox); QVERIFY(!buttonBox->button(QDialogButtonBox::Ok)->isEnabled()); searchLineEdit = widget->findChild(QStringLiteral("searchLineEdit")); QVERIFY(searchLineEdit); subscribedOnlyChkBox = widget->findChild(QStringLiteral("subscribedOnlyCheckBox")); QVERIFY(subscribedOnlyChkBox); collectionView = widget->findChild(QStringLiteral("collectionView")); QVERIFY(collectionView); subscribeButton = widget->findChild(QStringLiteral("subscribeButton")); QVERIFY(subscribeButton); unsubscribeButton = widget->findChild(QStringLiteral("unsubscribeButton")); QVERIFY(unsubscribeButton); QVERIFY(QTest::qWaitForWindowActive(widget.get())); QVERIFY(modelLoadedSpy.wait()); QTest::qWait(100); // Helps with testing :) collectionView->expandAll(); // Post-setup conditions QCOMPARE(countTotalRows(), defaultCollectionCount); QVERIFY(buttonBox->button(QDialogButtonBox::Ok)->isEnabled()); valid = true; } ~TestSetup() { } int countTotalRows(const QModelIndex &parent = {}) const { const auto count = collectionView->model()->rowCount(parent); int total = count; for (int i = 0; i < count; ++i) { total += countTotalRows(collectionView->model()->index(i, 0, parent)); } return total; } static bool unsubscribeCollection(const Collection &col) { return modifySubscription({}, {col}); } static bool subscribeCollection(const Collection &col) { return modifySubscription({col}, {}); } static bool modifySubscription(const Collection::List &subscribe, const Collection::List &unsubscribe) { auto job = new SubscriptionJob(); job->subscribe(subscribe); job->unsubscribe(unsubscribe); bool ok = false; [job, &ok]() { AKVERIFYEXEC(job); ok = true; }(); AKVERIFY(ok); return true; } bool selectCollection(const Collection &col) { AKVERIFY(col.isValid()); const QModelIndex colIdx = indexForCollection(col); AKVERIFY(colIdx.isValid()); collectionView->scrollTo(colIdx); QTest::mouseClick(collectionView->viewport(), Qt::LeftButton, {}, collectionView->visualRect(colIdx).center()); AKCOMPARE(collectionView->currentIndex(), colIdx); return true; } bool isCollectionChecked(const Collection &col) const { AKVERIFY(col.isValid()); const auto colIdx = indexForCollection(col); AKVERIFY(colIdx.isValid()); return collectionView->model()->data(colIdx, Qt::CheckStateRole).value() == Qt::Checked; } void acceptDialog() { auto button = buttonBox->button(QDialogButtonBox::Ok); QTest::mouseClick(button, Qt::LeftButton); } QModelIndex indexForCollection(const Collection &col) const { auto model = collectionView->model(); std::deque idxQueue; idxQueue.push_back(QModelIndex{}); while (!idxQueue.empty()) { const auto idx = idxQueue.front(); idxQueue.pop_front(); if (model->data(idx, EntityTreeModel::CollectionIdRole).value() == col.id()) { return idx; } for (int i = 0; i < model->rowCount(idx); ++i) { idxQueue.push_back(model->index(i, 0, idx)); } } return {}; } std::unique_ptr widget; QDialogButtonBox *buttonBox = nullptr; QLineEdit *searchLineEdit = nullptr; QCheckBox *subscribedOnlyChkBox = nullptr; QTreeView *collectionView = nullptr; QPushButton *subscribeButton = nullptr; QPushButton *unsubscribeButton = nullptr; SubscriptionModel *model = nullptr; bool valid = false; }; private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testSearchFilter() { TestSetup test; QVERIFY(test.valid); QTest::keyClicks(test.searchLineEdit, QStringLiteral("foo")); QCOMPARE(test.countTotalRows(), 2); } void testSubscribedOnlyCheckbox() { - const auto col = Collection{collectionIdFromPath(QStringLiteral("res1/foo/bla"))}; + const auto col = Collection{AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bla"))}; const AkScopeGuard guard([col]() { TestSetup::subscribeCollection(col); }); QVERIFY(TestSetup::unsubscribeCollection(col)); TestSetup test; QVERIFY(test.valid); test.subscribedOnlyChkBox->setChecked(true); QTRY_COMPARE(test.countTotalRows(), test.defaultCollectionCount - 1); test.subscribedOnlyChkBox->setChecked(false); QTRY_COMPARE(test.countTotalRows(), test.defaultCollectionCount); } void testSubscribeButton() { - const auto col = Collection{collectionIdFromPath(QStringLiteral("res1/foo/bla"))}; + const auto col = Collection{AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bla"))}; const AkScopeGuard guard([col]() { TestSetup::subscribeCollection(col); }); QVERIFY(TestSetup::unsubscribeCollection(col)); TestSetup test; QVERIFY(test.valid); QVERIFY(test.selectCollection(col)); QTest::mouseClick(test.subscribeButton, Qt::LeftButton); QVERIFY(test.isCollectionChecked(col)); - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy monitorSpy(monitor.get(), &Monitor::collectionSubscribed); test.acceptDialog(); QVERIFY(monitorSpy.wait()); } void testUnsubscribeButton() { - const auto col = Collection{collectionIdFromPath(QStringLiteral("res1/foo/bla"))}; + const auto col = Collection{AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bla"))}; TestSetup test; QVERIFY(test.valid); QVERIFY(test.selectCollection(col)); QTest::mouseClick(test.unsubscribeButton, Qt::LeftButton); QVERIFY(!test.isCollectionChecked(col)); - auto monitor = getTestMonitor(); + auto monitor = AkonadiTest::getTestMonitor(); QSignalSpy monitorSpy(monitor.get(), &Monitor::collectionUnsubscribed); test.acceptDialog(); QVERIFY(monitorSpy.wait()); } }; QTEST_AKONADIMAIN(SubscriptionDialogTest) #include "subscriptiondialogtest.moc" diff --git a/autotests/widgets/tagselectioncomboboxtest.cpp b/autotests/widgets/tagselectioncomboboxtest.cpp index afd7b8b23..7271e924b 100644 --- a/autotests/widgets/tagselectioncomboboxtest.cpp +++ b/autotests/widgets/tagselectioncomboboxtest.cpp @@ -1,245 +1,241 @@ /* * Copyright 2020 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "qtest_akonadi.h" -#include -#include -#include -#include #include #include "tagselectioncombobox.h" #include "tagmodel.h" #include "monitor.h" #include "tag.h" #include "tagdeletejob.h" #include "tagcreatejob.h" #include #include #include #include #include using namespace Akonadi; class TagSelectionComboBoxTest: public QObject { Q_OBJECT struct TestSetup { TestSetup(bool checkable) { widget = std::make_unique(); widget->setCheckable(checkable); widget->show(); monitor = widget->findChild(); QVERIFY(monitor); model = widget->findChild(); QVERIFY(model); QSignalSpy modelSpy(model, &TagModel::populated); QVERIFY(modelSpy.wait()); QVERIFY(QTest::qWaitForWindowActive(widget.get())); valid = true; } ~TestSetup() { if (!createdTags.empty()) { auto deleteJob = new TagDeleteJob(createdTags); AKVERIFYEXEC(deleteJob); } } bool createTags(int count) { const auto doCreateTags = [this, count]() { QSignalSpy monitorSpy(monitor, &Monitor::tagAdded); for (int i = 0; i < count; ++i) { auto job = new TagCreateJob(Tag(QStringLiteral("TestTag-%1").arg(i))); AKVERIFYEXEC(job); createdTags.push_back(job->tag()); } QTRY_COMPARE(monitorSpy.count(), count); }; doCreateTags(); return createdTags.size() == count; } bool testSelectionMatches(QSignalSpy &selectionSpy, const Tag::List &selection) { QStringList names; std::transform(selection.begin(), selection.end(), std::back_inserter(names), std::bind(&Tag::name, std::placeholders::_1)); AKCOMPARE(widget->selection(), selection); AKCOMPARE(widget->selectionNames(), names); AKCOMPARE(selectionSpy.size(), 1); AKCOMPARE(selectionSpy.at(0).at(0).value(), selection); AKCOMPARE(widget->currentText(), QLocale{}.createSeparatedList(names)); return true; } bool selectTagsInComboBox(const Tag::List &/*selection*/) { const auto windows = QApplication::topLevelWidgets(); for (auto *window : windows) { if (auto *combo = qobject_cast(window)) { QTest::mouseClick(combo, Qt::LeftButton); return true; } } return false; } bool toggleDropdown() { auto view = widget->view()->parentWidget(); const bool visible = view->isVisible(); QTest::mouseClick(widget->lineEdit(), Qt::LeftButton); QTest::qWait(10); AKCOMPARE(view->isVisible(), !visible); return true; } QModelIndex indexForTag(const Tag &tag) { for (int i = 0; i < widget->model()->rowCount(); ++i) { const auto index = widget->model()->index(i, 0); if (widget->model()->data(index, TagModel::TagRole).value().name() == tag.name()) { return index; } } return {}; } std::unique_ptr widget; Monitor *monitor = nullptr; TagModel *model = nullptr; Tag::List createdTags; bool valid = false; }; public: TagSelectionComboBoxTest() { qRegisterMetaType(); } private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testInitialState() { TestSetup test{true}; QVERIFY(test.valid); QVERIFY(test.widget->currentText().isEmpty()); QVERIFY(test.widget->selection().isEmpty()); } void testSettingSelectionFromCode() { TestSetup test{true}; QVERIFY(test.valid); QVERIFY(test.createTags(4)); QSignalSpy selectionSpy(test.widget.get(), &TagSelectionComboBox::selectionChanged); const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]}; test.widget->setSelection(selection); QVERIFY(test.testSelectionMatches(selectionSpy, selection)); } void testSettingSelectionByName() { TestSetup test{true}; QVERIFY(test.valid); QVERIFY(test.createTags(4)); QSignalSpy selectionSpy(test.widget.get(), &TagSelectionComboBox::selectionChanged); const auto selection = QStringList{test.createdTags[1].name(), test.createdTags[3].name()}; test.widget->setSelection(selection); QVERIFY(test.testSelectionMatches(selectionSpy, {test.createdTags[1], test.createdTags[3]})); } void testSelectionByKeyboard() { TestSetup test{true}; QVERIFY(test.valid); QVERIFY(test.createTags(4)); QSignalSpy selectionSpy(test.widget.get(), &TagSelectionComboBox::selectionChanged); const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]}; QVERIFY(!test.widget->view()->parentWidget()->isVisible()); QVERIFY(test.toggleDropdown()); QTest::keyClick(test.widget->view(), Qt::Key_Down); // from name to tag 1 QTest::keyClick(test.widget->view(), Qt::Key_Down); // from tag 1 to tag 2 QTest::keyClick(test.widget->view(), Qt::Key_Space); // select tag 2 QTest::keyClick(test.widget->view(), Qt::Key_Down); // from tag 2 to tag 3 QTest::keyClick(test.widget->view(), Qt::Key_Down); // from tag 3 to tag 4 QTest::keyClick(test.widget->view(), Qt::Key_Space); // select tag 4 QTest::keyClick(test.widget->view(), Qt::Key_Escape); // close QTest::qWait(100); QVERIFY(!test.widget->view()->parentWidget()->isVisible()); QCOMPARE(selectionSpy.size(), 2); // two selections -> two signals selectionSpy.takeFirst(); // remove the first one QVERIFY(test.testSelectionMatches(selectionSpy, selection)); } void testNonCheckableSelection() { TestSetup test{false}; QVERIFY(test.valid); QVERIFY(test.createTags(4)); test.widget->setCurrentIndex(1); QCOMPARE(test.widget->currentData(TagModel::TagRole).value(), test.createdTags[0]); QCOMPARE(test.widget->selection(), Tag::List{test.createdTags[0]}); QCOMPARE(test.widget->selectionNames(), QStringList{test.createdTags[0].name()}); test.widget->setSelection({test.createdTags[1]}); QCOMPARE(test.widget->currentIndex(), 2); } }; QTEST_AKONADIMAIN(TagSelectionComboBoxTest) #include "tagselectioncomboboxtest.moc" diff --git a/autotests/widgets/tagwidgettest.cpp b/autotests/widgets/tagwidgettest.cpp index 1ee62fe1b..75977d469 100644 --- a/autotests/widgets/tagwidgettest.cpp +++ b/autotests/widgets/tagwidgettest.cpp @@ -1,211 +1,208 @@ /* * Copyright 2020 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "qtest_akonadi.h" -#include -#include -#include #include #include "tagwidget.h" #include "tagselectiondialog.h" #include "tagmodel.h" #include "monitor.h" #include "tag.h" #include "tagdeletejob.h" #include "tagcreatejob.h" #include #include #include #include #include #include #include using namespace Akonadi; class TagWidgetTest: public QObject { Q_OBJECT struct TestSetup { TestSetup() { widget = std::make_unique(); widget->show(); monitor = widget->findChild(); QVERIFY(monitor); model = widget->findChild(); QVERIFY(model); QSignalSpy modelSpy(model, &TagModel::populated); QVERIFY(modelSpy.wait()); QVERIFY(QTest::qWaitForWindowActive(widget.get())); tagView = widget->findChild(QStringLiteral("tagView")); QVERIFY(tagView); QVERIFY(tagView->isReadOnly()); // always read-only editButton = widget->findChild(QStringLiteral("editButton")); QVERIFY(editButton); valid = true; } ~TestSetup() { if (!createdTags.empty()) { auto deleteJob = new TagDeleteJob(createdTags); AKVERIFYEXEC(deleteJob); } } bool createTags(int count) { const auto doCreateTags = [this, count]() { QSignalSpy monitorSpy(monitor, &Monitor::tagAdded); for (int i = 0; i < count; ++i) { auto job = new TagCreateJob(Tag(QStringLiteral("TestTag-%1").arg(i))); AKVERIFYEXEC(job); createdTags.push_back(job->tag()); } QTRY_COMPARE(monitorSpy.count(), count); }; doCreateTags(); return createdTags.size() == count; } bool testSelectionMatches(QSignalSpy &selectionSpy, const Tag::List &selection) { QStringList names; std::transform(selection.begin(), selection.end(), std::back_inserter(names), std::bind(&Tag::name, std::placeholders::_1)); AKCOMPARE(widget->selection(), selection); AKCOMPARE(selectionSpy.size(), 1); AKCOMPARE(selectionSpy.at(0).at(0).value(), selection); AKCOMPARE(tagView->text(), names.join(QStringLiteral(", "))); return true; } bool selectTagsInDialog(const Tag::List &selection) { const auto windows = QApplication::topLevelWidgets(); for (auto *window : windows) { if (auto *dlg = qobject_cast(window)) { // Set the selection through code, testing selecting tags with mouse is // out-of-scope for this test, there's a dedicated TagEditWidget test for that. dlg->setSelection(selection); auto *button = dlg->buttons()->button(QDialogButtonBox::Ok); AKVERIFY(button); QTest::mouseClick(button, Qt::LeftButton); return true; } } return false; } std::unique_ptr widget; Monitor *monitor = nullptr; TagModel *model = nullptr; QLineEdit *tagView = nullptr; QToolButton *editButton = nullptr; Tag::List createdTags; bool valid = false; }; private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testInitialState() { TestSetup test; QVERIFY(test.valid); QVERIFY(test.tagView->text().isEmpty()); QVERIFY(test.widget->selection().isEmpty()); } void testSettingSelectionFromCode() { TestSetup test; QVERIFY(test.valid); QVERIFY(test.createTags(4)); QSignalSpy selectionSpy(test.widget.get(), &TagWidget::selectionChanged); const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]}; test.widget->setSelection(selection); QVERIFY(test.testSelectionMatches(selectionSpy, selection)); } void testSettingSelectionViaDialog() { TestSetup test; QVERIFY(test.valid); QVERIFY(test.createTags(4)); QSignalSpy selectionSpy(test.widget.get(), &TagWidget::selectionChanged); const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]}; bool ok = false; // Clicking on the Edit button opens the dialog in a blocking way, so // we need to dispatch the test from event loop QTimer::singleShot(100, this, [&test, &selection, &ok]() { QVERIFY(test.selectTagsInDialog(selection)); ok = true; }); QTest::mouseClick(test.editButton, Qt::LeftButton); QVERIFY(ok); QVERIFY(test.testSelectionMatches(selectionSpy, selection)); } void testClearTagsFromCode() { TestSetup test; QVERIFY(test.valid); QVERIFY(test.createTags(4)); const auto selection = Tag::List{test.createdTags[1], test.createdTags[3]}; test.widget->setSelection(selection); QCOMPARE(test.widget->selection(), selection); QSignalSpy selectionSpy(test.widget.get(), &TagWidget::selectionChanged); test.widget->clearTags(); QVERIFY(test.widget->selection().isEmpty()); QCOMPARE(selectionSpy.size(), 1); QVERIFY(selectionSpy.at(0).at(0).value().empty()); QVERIFY(test.tagView->text().isEmpty()); } }; QTEST_AKONADIMAIN(TagWidgetTest) #include "tagwidgettest.moc" diff --git a/src/core/qtest_akonadi.h b/src/core/qtest_akonadi.h index b9917ba91..fbf0422e3 100644 --- a/src/core/qtest_akonadi.h +++ b/src/core/qtest_akonadi.h @@ -1,125 +1,216 @@ /* This file is based on qtest_kde.h from kdelibs Copyright (C) 2006 David Faure Copyright (C) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef QTEST_AKONADI_H #define QTEST_AKONADI_H -#include -#include +#include "agentinstance.h" +#include "agentmanager.h" +#include "servermanager.h" +#include "collectionpathresolver.h" +#include "monitor.h" +#include "collectionfetchscope.h" +#include "itemfetchscope.h" #include #include #include +#include +#include +#include /** * \short Akonadi Replacement for QTEST_MAIN from QTestLib * * This macro should be used for classes that run inside the Akonadi Testrunner. * So instead of writing QTEST_MAIN( TestClass ) you write * QTEST_AKONADIMAIN( TestClass ). * * Unlike QTEST_MAIN, this macro actually does call QApplication::exec() so * that the application is running during test execution. This is needed * for proper clean up of Sessions. * * \param TestObject The class you use for testing. * * \see QTestLib * \see QTEST_KDEMAIN */ #define QTEST_AKONADIMAIN(TestObject) \ int main(int argc, char *argv[]) \ { \ qputenv("LC_ALL", "C"); \ qunsetenv("KDE_COLOR_DEBUG"); \ QApplication app(argc, argv); \ app.setApplicationName(QStringLiteral("qttest")); \ app.setOrganizationDomain(QStringLiteral("kde.org")); \ app.setOrganizationName(QStringLiteral("KDE")); \ QGuiApplication::setQuitOnLastWindowClosed(false); \ qRegisterMetaType>(); \ int result = 0; \ QTimer::singleShot(0, [argc, argv, &result]() { \ TestObject tc; \ result = QTest::qExec(&tc, argc, argv); \ qApp->quit(); \ }); \ app.exec(); \ return result; \ } namespace AkonadiTest { /** * Checks that the test is running in the proper test environment */ void checkTestIsIsolated() { if (qEnvironmentVariableIsEmpty("TESTRUNNER_DB_ENVIRONMENT")) qFatal("This test must be run using ctest, in order to use the testrunner environment. Aborting, to avoid messing up your real akonadi"); if (!qgetenv("XDG_DATA_HOME").contains("testrunner")) qFatal("Did you forget to run the test using QTEST_AKONADIMAIN?"); } /** * Switch all resources offline to reduce interference from them */ void setAllResourcesOffline() { // switch all resources offline to reduce interference from them const auto lst = Akonadi::AgentManager::self()->instances(); for (Akonadi::AgentInstance agent : lst) { agent.setIsOnline(false); } } template bool akWaitForSignal(Object sender, Func member, int timeout = 1000) { QSignalSpy spy(sender, member); bool ok = false; [&]() { QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, timeout); ok = true; }(); return ok; } bool akWaitForSignal(const QObject *sender, const char *member, int timeout = 1000) { QSignalSpy spy(sender, member); bool ok = false; [&]() { QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, timeout); ok = true; }(); return ok; } +qint64 collectionIdFromPath(const QString &path) +{ + Akonadi::CollectionPathResolver *resolver = new Akonadi::CollectionPathResolver(path); + bool success = resolver->exec(); + if (!success) { + qDebug() << "path resolution for " << path << " failed: " << resolver->errorText(); + return -1; + } + qint64 id = resolver->collection(); + return id; +} + +QString testrunnerServiceName() +{ + const QString pid = QString::fromLocal8Bit(qgetenv("AKONADI_TESTRUNNER_PID")); + Q_ASSERT(!pid.isEmpty()); + return QStringLiteral("org.kde.Akonadi.Testrunner-") + pid; +} + +bool restartAkonadiServer() +{ + QDBusInterface testrunnerIface(testrunnerServiceName(), + QStringLiteral("/"), + QStringLiteral("org.kde.Akonadi.Testrunner"), + QDBusConnection::sessionBus()); + if (!testrunnerIface.isValid()) { + qWarning() << "Unable to get a dbus interface to the testrunner!"; + } + + QDBusReply reply = testrunnerIface.call(QStringLiteral("restartAkonadiServer")); + if (!reply.isValid()) { + qWarning() << reply.error(); + return false; + } else if (Akonadi::ServerManager::isRunning()) { + return true; + } else { + bool ok = false; + [&]() { + QSignalSpy spy(Akonadi::ServerManager::self(), &Akonadi::ServerManager::started); + QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 10000); + ok = true; + }(); + return ok; + } +} + +bool trackAkonadiProcess(bool track) +{ + QDBusInterface testrunnerIface(testrunnerServiceName(), + QStringLiteral("/"), + QStringLiteral("org.kde.Akonadi.Testrunner"), + QDBusConnection::sessionBus()); + if (!testrunnerIface.isValid()) { + qWarning() << "Unable to get a dbus interface to the testrunner!"; + } + + QDBusReply reply = testrunnerIface.call(QStringLiteral("trackAkonadiProcess"), track); + if (!reply.isValid()) { + qWarning() << reply.error(); + return false; + } else { + return true; + } +} + +std::unique_ptr getTestMonitor() +{ + auto m = new Akonadi::Monitor(); + m->fetchCollection(true); + m->setCollectionMonitored(Akonadi::Collection::root(), true); + m->setAllMonitored(true); + auto &itemFS = m->itemFetchScope(); + itemFS.setAncestorRetrieval(Akonadi::ItemFetchScope::All); + auto &colFS = m->collectionFetchScope(); + colFS.setAncestorRetrieval(Akonadi::CollectionFetchScope::All); + + QSignalSpy readySpy(m, &Akonadi::Monitor::monitorReady); + readySpy.wait(); + + return std::unique_ptr(m); +} + + } // namespace /** * Runs an Akonadi::Job synchronously and aborts if the job failed. * Similar to QVERIFY( job->exec() ) but includes the job error message * in the output in case of a failure. */ #define AKVERIFYEXEC( job ) \ QVERIFY2( job->exec(), job->errorString().toUtf8().constData() ) #endif