diff --git a/akonadi/tests/itemstoretest.cpp b/akonadi/tests/itemstoretest.cpp index 5d2fdb0d2..33c87c8ba 100644 --- a/akonadi/tests/itemstoretest.cpp +++ b/akonadi/tests/itemstoretest.cpp @@ -1,382 +1,387 @@ /* 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 "control.h" #include "itemstoretest.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, NoGUI ) static Collection res1_foo; static Collection res2; static Collection res3; void ItemStoreTest::initTestCase() { Control::start(); AttributeFactory::registerAttribute(); // get the collections we run the tests on res1_foo = Collection( collectionIdFromPath( "res1/foo" ) ); QVERIFY( res1_foo.isValid() ); res2 = Collection( collectionIdFromPath( "res2" ) ); QVERIFY( res2.isValid() ); res3 = Collection( collectionIdFromPath( "res3" ) ); QVERIFY( res3.isValid() ); // switch all resources offline to reduce interference from them foreach ( Akonadi::AgentInstance agent, Akonadi::AgentManager::self()->instances() ) agent.setIsOnline( false ); } 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( "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(); 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() ) ); QEXPECT_FAIL( "null", "Serializer cannot distinguish null vs. empty", Continue ); QCOMPARE( item.payload().isNull(), data.isNull() ); } void ItemStoreTest::testRemoteId_data() { QTest::addColumn( "rid" ); QTest::addColumn( "exprid" ); QTest::newRow( "set" ) << QString( "A" ) << QString( "A" ); QTest::newRow( "no-change" ) << QString() << QString( "A" ); QTest::newRow( "clear" ) << QString( "" ) << QString( "" ); QTest::newRow( "reset" ) << QString( "A" ) << QString( "A" ); QTest::newRow( "utf8" ) << QString( "ä ö ü @" ) << QString( "ä ö ü @" ); } void ItemStoreTest::testRemoteId() { QFETCH( QString, rid ); QFETCH( QString, exprid ); // pretend to be a resource, we cannot change remote identifiers otherwise ResourceSelectJob *rsel = new ResourceSelectJob( "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 ); AKVERIFYEXEC( store ); ItemFetchJob *fetch = new ItemFetchJob( item, this ); AKVERIFYEXEC( fetch ); QCOMPARE( fetch->items().count(), 1 ); item = fetch->items().at( 0 ); 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 ) ); QVERIFY( prefetchjob->exec() ); QCOMPARE( prefetchjob->items().count(), 1 ); Item item = prefetchjob->items()[0]; item.setMimeType( "application/octet-stream" ); item.setPayload( "testmailbody" ); item.attribute( Item::AddIfMissing )->data = "extra"; // store item ItemModifyJob *sjob = new ItemModifyJob( item ); QVERIFY( sjob->exec() ); ItemFetchJob *fjob = new ItemFetchJob( Item( 1 ) ); fjob->fetchScope().fetchAttribute(); fjob->fetchScope().fetchFullPayload(); QVERIFY( fjob->exec() ); 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 ); QVERIFY( sjob->exec() ); } void ItemStoreTest::testPartRemove() { ItemFetchJob *prefetchjob = new ItemFetchJob( Item( 2 ) ); prefetchjob->exec(); Item item = prefetchjob->items()[0]; item.setMimeType( "application/octet-stream" ); item.attribute( Item::AddIfMissing )->data = "extra"; // store item ItemModifyJob *sjob = new ItemModifyJob( item ); QVERIFY( sjob->exec() ); // fetch item and its parts (should be RFC822, HEAD and EXTRA) ItemFetchJob *fjob = new ItemFetchJob( Item( 2 ) ); fjob->fetchScope().fetchFullPayload(); fjob->fetchScope().fetchAllAttributes(); QVERIFY( fjob->exec() ); 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 ); QVERIFY( sjob->exec() ); // fetch item again (should only have RFC822 and HEAD left) ItemFetchJob *fjob2 = new ItemFetchJob( Item( 2 ) ); fjob2->fetchScope().fetchFullPayload(); fjob2->fetchScope().fetchAllAttributes(); QVERIFY( fjob2->exec() ); QCOMPARE( fjob2->items().count(), 1 ); item = fjob2->items()[0]; QCOMPARE( item.attributes().count(), 1 ); QVERIFY( !item.hasAttribute() ); } void ItemStoreTest::testRevisionCheck() { // make sure we don't have any other collection selected // otherwise EXPUNGE doesn't work and will be triggered by // the following tests and mess up the monitor testing CollectionSelectJob *sel = new CollectionSelectJob( Collection::root(), this ); QVERIFY( sel->exec() ); // fetch same item twice Item ref( 2 ); ItemFetchJob *prefetchjob = new ItemFetchJob( ref ); - QVERIFY( prefetchjob->exec() ); + 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 ); - QVERIFY( sjob->exec() ); + AKVERIFYEXEC( sjob ); - // try to store second item + // 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 ); - item2.attribute( Item::AddIfMissing )->data = "extra"; QVERIFY( !sjob2->exec() ); // fetch same again prefetchjob = new ItemFetchJob( ref ); - prefetchjob->exec(); + AKVERIFYEXEC( prefetchjob ); item1 = prefetchjob->items()[0]; // delete item ItemDeleteJob *djob = new ItemDeleteJob( ref, this ); - djob->exec(); + AKVERIFYEXEC( djob ); // try to store it sjob = new ItemModifyJob( item1 ); QVERIFY( !sjob->exec() ); } void ItemStoreTest::testModificationTime() { Item item; item.setMimeType( "text/directory" ); QVERIFY( item.modificationTime().isNull() ); ItemCreateJob *job = new ItemCreateJob( item, res1_foo ); QVERIFY( job->exec() ); // 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 ); QVERIFY( fjob->exec() ); item2 = fjob->items().first(); QCOMPARE( initialDateTime, item2.modificationTime() ); // Lets wait 5 secs. QTest::qWait( 5000 ); // Modify the item item.attribute( Item::AddIfMissing )->data = "extra"; ItemModifyJob *mjob = new ItemModifyJob( item ); QVERIFY( mjob->exec() ); // 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 ); QVERIFY( fjob2->exec() ); // 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 ); QVERIFY( idjob->exec() ); } void ItemStoreTest::testRemoteIdRace() { // Create an item and store it Item item; item.setMimeType( "text/directory" ); ItemCreateJob *job = new ItemCreateJob( item, res1_foo ); QVERIFY( job->exec() ); // 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 ); QVERIFY( fetchJob->exec() ); QCOMPARE( fetchJob->items().size(), 1 ); QVERIFY( fetchJob->items().first().remoteId().isNull() ); } #include "itemstoretest.moc"