File indexing completed on 2024-11-10 04:40:12
0001 /* 0002 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "itemappendtest.h" 0008 #include "qtest_akonadi.h" 0009 0010 #include "control.h" 0011 #include "testattribute.h" 0012 0013 #include "agentinstance.h" 0014 #include "agentmanager.h" 0015 #include "attributefactory.h" 0016 #include "collectionfetchjob.h" 0017 #include "config_p.h" 0018 #include "itemcreatejob.h" 0019 #include "itemdeletejob.h" 0020 #include "itemfetchjob.h" 0021 #include "itemfetchscope.h" 0022 0023 #include <QDebug> 0024 0025 using namespace Akonadi; 0026 0027 QTEST_AKONADIMAIN(ItemAppendTest) 0028 0029 void ItemAppendTest::initTestCase() 0030 { 0031 // The size checks in the test expects Item payload to not be compressed 0032 QVERIFY(!Config::get().payloadCompression.enabled); 0033 0034 AkonadiTest::checkTestIsIsolated(); 0035 Control::start(); 0036 AkonadiTest::setAllResourcesOffline(); 0037 AttributeFactory::registerAttribute<TestAttribute>(); 0038 AttributeFactory::registerAttribute<TestAttribute2>(); 0039 } 0040 0041 void ItemAppendTest::testItemAppend_data() 0042 { 0043 QTest::addColumn<QString>("remoteId"); 0044 0045 QTest::newRow("empty") << QString(); 0046 QTest::newRow("non empty") << QStringLiteral("remote-id"); 0047 QTest::newRow("whitespace") << QStringLiteral("remote id"); 0048 QTest::newRow("quotes") << QStringLiteral("\"remote\" id"); 0049 QTest::newRow("brackets") << QStringLiteral("[remote id]"); 0050 QTest::newRow("RID length limit") << QStringLiteral("a").repeated(1024); 0051 } 0052 0053 void ItemAppendTest::testItemAppend() 0054 { 0055 const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0056 QVERIFY(testFolder1.isValid()); 0057 0058 QFETCH(QString, remoteId); 0059 Item ref; // for cleanup 0060 0061 Item item(-1); 0062 item.setRemoteId(remoteId); 0063 item.setMimeType(QStringLiteral("application/octet-stream")); 0064 item.setFlag("TestFlag"); 0065 item.setSize(3456); 0066 auto job = new ItemCreateJob(item, testFolder1, this); 0067 AKVERIFYEXEC(job); 0068 ref = job->item(); 0069 QCOMPARE(ref.parentCollection(), testFolder1); 0070 0071 auto fjob = new ItemFetchJob(testFolder1, this); 0072 fjob->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent); 0073 AKVERIFYEXEC(fjob); 0074 QCOMPARE(fjob->items().count(), 1); 0075 QCOMPARE(fjob->items()[0], ref); 0076 QCOMPARE(fjob->items()[0].remoteId(), remoteId); 0077 QVERIFY(fjob->items()[0].flags().contains("TestFlag")); 0078 QCOMPARE(fjob->items()[0].parentCollection(), ref.parentCollection()); 0079 0080 qint64 size = 3456; 0081 QCOMPARE(fjob->items()[0].size(), size); 0082 0083 auto djob = new ItemDeleteJob(ref, this); 0084 AKVERIFYEXEC(djob); 0085 0086 fjob = new ItemFetchJob(testFolder1, this); 0087 AKVERIFYEXEC(fjob); 0088 QVERIFY(fjob->items().isEmpty()); 0089 } 0090 0091 void ItemAppendTest::testContent_data() 0092 { 0093 QTest::addColumn<QByteArray>("data"); 0094 0095 QTest::newRow("null") << QByteArray(); 0096 QTest::newRow("empty") << QByteArray(""); 0097 QTest::newRow("nullbyte") << QByteArray("\0", 1); 0098 QTest::newRow("nullbyte3") << QByteArray("\0X", 2); 0099 QString utf8string = QStringLiteral("äöüß@€µøđ¢©®"); 0100 QTest::newRow("utf8") << utf8string.toUtf8(); 0101 QTest::newRow("newlines") << QByteArray("\nsome\n\nbreaked\ncontent\n\n"); 0102 QByteArray b; 0103 QTest::newRow("big") << b.fill('a', 1U << 20); 0104 QTest::newRow("bignull") << b.fill('\0', 1U << 20); 0105 QTest::newRow("bigcr") << b.fill('\r', 1U << 20); 0106 QTest::newRow("biglf") << b.fill('\n', 1U << 20); 0107 } 0108 0109 void ItemAppendTest::testContent() 0110 { 0111 const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0112 QVERIFY(testFolder1.isValid()); 0113 0114 QFETCH(QByteArray, data); 0115 0116 Item item; 0117 item.setMimeType(QStringLiteral("application/octet-stream")); 0118 if (!data.isNull()) { 0119 item.setPayload(data); 0120 } 0121 0122 auto job = new ItemCreateJob(item, testFolder1, this); 0123 AKVERIFYEXEC(job); 0124 Item ref = job->item(); 0125 0126 auto fjob = new ItemFetchJob(testFolder1, this); 0127 fjob->fetchScope().setCacheOnly(true); 0128 fjob->fetchScope().fetchFullPayload(); 0129 AKVERIFYEXEC(fjob); 0130 QCOMPARE(fjob->items().count(), 1); 0131 Item item2 = fjob->items().first(); 0132 QCOMPARE(item2.hasPayload(), !data.isNull()); 0133 if (item2.hasPayload()) { 0134 QCOMPARE(item2.payload<QByteArray>(), data); 0135 } 0136 0137 auto djob = new ItemDeleteJob(ref, this); 0138 AKVERIFYEXEC(djob); 0139 } 0140 0141 void ItemAppendTest::testNewMimetype() 0142 { 0143 const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0144 QVERIFY(col.isValid()); 0145 0146 Item item; 0147 item.setMimeType(QStringLiteral("application/new-type")); 0148 auto job = new ItemCreateJob(item, col, this); 0149 AKVERIFYEXEC(job); 0150 0151 item = job->item(); 0152 QVERIFY(item.isValid()); 0153 0154 auto fetch = new ItemFetchJob(item, this); 0155 AKVERIFYEXEC(fetch); 0156 QCOMPARE(fetch->items().count(), 1); 0157 QCOMPARE(fetch->items().first().mimeType(), item.mimeType()); 0158 } 0159 0160 void ItemAppendTest::testIllegalAppend() 0161 { 0162 const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0163 QVERIFY(testFolder1.isValid()); 0164 0165 Item item; 0166 item.setMimeType(QStringLiteral("application/octet-stream")); 0167 0168 // adding item to non-existing collection 0169 auto job = new ItemCreateJob(item, Collection(INT_MAX), this); 0170 QVERIFY(!job->exec()); 0171 0172 // adding item into a collection which can't handle items of this type 0173 const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo/bla"))); 0174 QVERIFY(col.isValid()); 0175 job = new ItemCreateJob(item, col, this); 0176 QEXPECT_FAIL("", "Test not yet implemented in the server.", Continue); 0177 QVERIFY(!job->exec()); 0178 } 0179 0180 void ItemAppendTest::testMultipartAppend() 0181 { 0182 const Collection testFolder1(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0183 QVERIFY(testFolder1.isValid()); 0184 0185 Item item; 0186 item.setMimeType(QStringLiteral("application/octet-stream")); 0187 item.setPayload<QByteArray>("body data"); 0188 item.attribute<TestAttribute>(Item::AddIfMissing)->data = "extra data"; 0189 item.setFlag("TestFlag"); 0190 auto job = new ItemCreateJob(item, testFolder1, this); 0191 AKVERIFYEXEC(job); 0192 Item ref = job->item(); 0193 0194 auto fjob = new ItemFetchJob(ref, this); 0195 fjob->fetchScope().fetchFullPayload(); 0196 fjob->fetchScope().fetchAttribute<TestAttribute>(); 0197 AKVERIFYEXEC(fjob); 0198 QCOMPARE(fjob->items().count(), 1); 0199 item = fjob->items().first(); 0200 QCOMPARE(item.payload<QByteArray>(), QByteArray("body data")); 0201 QVERIFY(item.hasAttribute<TestAttribute>()); 0202 QCOMPARE(item.attribute<TestAttribute>()->data, QByteArray("extra data")); 0203 QVERIFY(item.flags().contains("TestFlag")); 0204 0205 auto djob = new ItemDeleteJob(ref, this); 0206 AKVERIFYEXEC(djob); 0207 } 0208 0209 void ItemAppendTest::testInvalidMultipartAppend() 0210 { 0211 Item item; 0212 item.setMimeType(QStringLiteral("application/octet-stream")); 0213 item.setPayload<QByteArray>("body data"); 0214 item.attribute<TestAttribute>(Item::AddIfMissing)->data = "extra data"; 0215 item.attribute<TestAttribute2>(Item::AddIfMissing)->data = "more extra data"; 0216 item.setFlag("TestFlag"); 0217 auto job = new ItemCreateJob(item, Collection(-1), this); 0218 QVERIFY(!job->exec()); 0219 0220 Item item2; 0221 item2.setMimeType(QStringLiteral("application/octet-stream")); 0222 item2.setPayload<QByteArray>("more body data"); 0223 // Note the inverted order - intentional, but shouldn't impact the test in any way. 0224 item2.attribute<TestAttribute2>(Item::AddIfMissing)->data = "absolute horde of extra data"; 0225 item2.attribute<TestAttribute>(Item::AddIfMissing)->data = "even more extra data"; 0226 item2.setFlag("TestFlag"); 0227 auto job2 = new ItemCreateJob(item2, Collection(-1), this); 0228 QVERIFY(!job2->exec()); 0229 } 0230 0231 void ItemAppendTest::testItemSize_data() 0232 { 0233 QTest::addColumn<Akonadi::Item>("item"); 0234 QTest::addColumn<qint64>("size"); 0235 0236 Item i(QStringLiteral("application/octet-stream")); 0237 i.setPayload(QByteArray("ABCD")); 0238 0239 QTest::newRow("auto size") << i << 4LL; 0240 i.setSize(3); 0241 QTest::newRow("too small") << i << 4LL; 0242 i.setSize(100); 0243 QTest::newRow("too large") << i << 100LL; 0244 } 0245 0246 void ItemAppendTest::testItemSize() 0247 { 0248 QFETCH(Akonadi::Item, item); 0249 QFETCH(qint64, size); 0250 0251 const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0252 QVERIFY(col.isValid()); 0253 0254 auto create = new ItemCreateJob(item, col, this); 0255 AKVERIFYEXEC(create); 0256 Item newItem = create->item(); 0257 0258 auto fetch = new ItemFetchJob(newItem, this); 0259 AKVERIFYEXEC(fetch); 0260 QCOMPARE(fetch->items().count(), 1); 0261 0262 QCOMPARE(fetch->items().first().size(), size); 0263 } 0264 0265 void ItemAppendTest::testItemMerge_data() 0266 { 0267 QTest::addColumn<Akonadi::Item>("item1"); 0268 QTest::addColumn<Akonadi::Item>("item2"); 0269 QTest::addColumn<Akonadi::Item>("mergedItem"); 0270 QTest::addColumn<bool>("silent"); 0271 0272 { 0273 Item i1(QStringLiteral("application/octet-stream")); 0274 i1.setPayload(QByteArray("ABCD")); 0275 i1.setSize(56); // take compression into account 0276 i1.setRemoteId(QStringLiteral("XYZ")); 0277 i1.setGid(QStringLiteral("XYZ")); 0278 i1.setFlag("TestFlag1"); 0279 i1.setRemoteRevision(QStringLiteral("5")); 0280 0281 Item i2(QStringLiteral("application/octet-stream")); 0282 i2.setPayload(QByteArray("DEFGH")); 0283 i2.setSize(60); // the compression into account 0284 i2.setRemoteId(QStringLiteral("XYZ")); 0285 i2.setGid(QStringLiteral("XYZ")); 0286 i2.setFlag("TestFlag2"); 0287 i2.setRemoteRevision(QStringLiteral("6")); 0288 0289 Item mergedItem(i2); 0290 mergedItem.setFlag("TestFlag1"); 0291 0292 QTest::newRow("merge") << i1 << i2 << mergedItem << false; 0293 QTest::newRow("merge (silent)") << i1 << i2 << mergedItem << true; 0294 } 0295 { 0296 Item i1(QStringLiteral("application/octet-stream")); 0297 i1.setPayload(QByteArray("ABCD")); 0298 i1.setSize(56); // take compression into account 0299 i1.setRemoteId(QStringLiteral("RID2")); 0300 i1.setGid(QStringLiteral("GID2")); 0301 i1.setFlag("TestFlag1"); 0302 i1.setRemoteRevision(QStringLiteral("5")); 0303 0304 Item i2(QStringLiteral("application/octet-stream")); 0305 i2.setRemoteId(QStringLiteral("RID2")); 0306 i2.setGid(QStringLiteral("GID2")); 0307 i2.setFlags(Item::Flags() << "TestFlag2"); 0308 i2.setRemoteRevision(QStringLiteral("6")); 0309 0310 Item mergedItem(i1); 0311 mergedItem.setFlags(i2.flags()); 0312 mergedItem.setRemoteRevision(i2.remoteRevision()); 0313 0314 QTest::newRow("overwrite flags, and don't remove existing payload") << i1 << i2 << mergedItem << false; 0315 QTest::newRow("overwrite flags, and don't remove existing payload (silent)") << i1 << i2 << mergedItem << true; 0316 } 0317 } 0318 0319 void ItemAppendTest::testItemMerge() 0320 { 0321 QFETCH(Akonadi::Item, item1); 0322 QFETCH(Akonadi::Item, item2); 0323 QFETCH(Akonadi::Item, mergedItem); 0324 QFETCH(bool, silent); 0325 0326 const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0327 QVERIFY(col.isValid()); 0328 0329 auto create = new ItemCreateJob(item1, col, this); 0330 AKVERIFYEXEC(create); 0331 const Item createdItem = create->item(); 0332 0333 auto merge = new ItemCreateJob(item2, col, this); 0334 ItemCreateJob::MergeOptions options = ItemCreateJob::GID | ItemCreateJob::RID; 0335 if (silent) { 0336 options |= ItemCreateJob::Silent; 0337 } 0338 merge->setMerge(options); 0339 AKVERIFYEXEC(merge); 0340 0341 QCOMPARE(merge->item().id(), createdItem.id()); 0342 if (!silent) { 0343 QCOMPARE(merge->item().gid(), mergedItem.gid()); 0344 QCOMPARE(merge->item().remoteId(), mergedItem.remoteId()); 0345 QCOMPARE(merge->item().remoteRevision(), mergedItem.remoteRevision()); 0346 QCOMPARE(merge->item().payloadData(), mergedItem.payloadData()); 0347 QCOMPARE(merge->item().size(), mergedItem.size()); 0348 qDebug() << merge->item().flags() << mergedItem.flags(); 0349 QCOMPARE(merge->item().flags(), mergedItem.flags()); 0350 } 0351 0352 if (merge->item().id() != createdItem.id()) { 0353 auto del = new ItemDeleteJob(merge->item(), this); 0354 AKVERIFYEXEC(del); 0355 } 0356 auto del = new ItemDeleteJob(createdItem, this); 0357 AKVERIFYEXEC(del); 0358 } 0359 0360 void ItemAppendTest::testForeignPayload() 0361 { 0362 const Collection col(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/space folder"))); 0363 QVERIFY(col.isValid()); 0364 0365 const QString filePath = QString::fromUtf8(qgetenv("TMPDIR")) + QStringLiteral("/foreignPayloadFile.mbox"); 0366 QFile file(filePath); 0367 QVERIFY(file.open(QIODevice::WriteOnly)); 0368 file.write("123456789"); 0369 file.close(); 0370 0371 Item item(QStringLiteral("application/octet-stream")); 0372 item.setPayloadPath(filePath); 0373 item.setRemoteId(QStringLiteral("RID3")); 0374 item.setSize(9); 0375 0376 auto create = new ItemCreateJob(item, col, this); 0377 AKVERIFYEXEC(create); 0378 0379 auto ref = create->item(); 0380 0381 auto fetch = new ItemFetchJob(ref, this); 0382 fetch->fetchScope().fetchFullPayload(true); 0383 AKVERIFYEXEC(fetch); 0384 const auto items = fetch->items(); 0385 QCOMPARE(items.size(), 1); 0386 item = items[0]; 0387 0388 QVERIFY(item.hasPayload<QByteArray>()); 0389 QCOMPARE(item.payload<QByteArray>(), QByteArray("123456789")); 0390 0391 auto del = new ItemDeleteJob(item, this); 0392 AKVERIFYEXEC(del); 0393 0394 // Make sure Akonadi does not delete a foreign payload 0395 QVERIFY(file.exists()); 0396 QVERIFY(file.remove()); 0397 } 0398 0399 #include "moc_itemappendtest.cpp"