diff --git a/autotests/libs/itemstoretest.cpp b/autotests/libs/itemstoretest.cpp index 2b461d30d..6547ae125 100644 --- a/autotests/libs/itemstoretest.cpp +++ b/autotests/libs/itemstoretest.cpp @@ -1,383 +1,384 @@ /* 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 #include #include #include #include #include #include #include #include #include #include #include #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"))); QVERIFY(res1_foo.isValid()); res2 = Collection(collectionIdFromPath(QStringLiteral("res2"))); QVERIFY(res2.isValid()); res3 = Collection(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()); }