File indexing completed on 2024-11-10 04:40:20
0001 /* 0002 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <QObject> 0008 #include <QSettings> 0009 0010 #include <qhashfunctions.h> 0011 #include <storage/selectquerybuilder.h> 0012 0013 #include "private/scope_p.h" 0014 #include "private/standarddirs_p.h" 0015 0016 #include "fakeakonadiserver.h" 0017 #include "fakeentities.h" 0018 0019 #include "shared/akranges.h" 0020 #include "shared/aktest.h" 0021 0022 #include <QTest> 0023 0024 using namespace Akonadi; 0025 using namespace Akonadi::Server; 0026 0027 Q_DECLARE_METATYPE(PimItem) 0028 Q_DECLARE_METATYPE(QList<Flag>) 0029 Q_DECLARE_METATYPE(QList<FakePart>) 0030 Q_DECLARE_METATYPE(QList<FakeTag>) 0031 0032 class ItemCreateHandlerTest : public QObject 0033 { 0034 Q_OBJECT 0035 0036 FakeAkonadiServer mAkonadi; 0037 0038 public: 0039 ItemCreateHandlerTest() 0040 { 0041 QHashSeed::setDeterministicGlobalSeed(); 0042 0043 // Effectively disable external payload parts, we have a dedicated unit-test 0044 // for that 0045 const QString serverConfigFile = StandardDirs::serverConfigFile(StandardDirs::ReadWrite); 0046 QSettings settings(serverConfigFile, QSettings::IniFormat); 0047 settings.setValue(QStringLiteral("General/SizeThreshold"), std::numeric_limits<qint64>::max()); 0048 0049 mAkonadi.init(); 0050 } 0051 0052 void updatePimItem(PimItem &pimItem, const QString &remoteId, const qint64 size) 0053 { 0054 pimItem.setRemoteId(remoteId); 0055 pimItem.setGid(remoteId); 0056 pimItem.setSize(size); 0057 } 0058 0059 void updateNotifcationEntity(Protocol::ItemChangeNotificationPtr &ntf, const PimItem &pimItem) 0060 { 0061 Protocol::FetchItemsResponse item; 0062 item.setId(pimItem.id()); 0063 item.setRemoteId(pimItem.remoteId()); 0064 item.setRemoteRevision(pimItem.remoteRevision()); 0065 item.setMimeType(pimItem.mimeType().name()); 0066 ntf->setItems({std::move(item)}); 0067 } 0068 0069 struct PartHelper { 0070 PartHelper(const QString &type_, const QByteArray &data_, qsizetype size_, Part::Storage storage_ = Part::Internal, int version_ = 0) 0071 : type(type_) 0072 , data(data_) 0073 , size(size_) 0074 , storage(storage_) 0075 , version(version_) 0076 { 0077 } 0078 QString type; 0079 QByteArray data; 0080 qsizetype size; 0081 Part::Storage storage; 0082 int version; 0083 }; 0084 0085 void updateParts(QList<FakePart> &parts, const std::vector<PartHelper> &updatedParts) 0086 { 0087 parts.clear(); 0088 for (const PartHelper &helper : updatedParts) { 0089 FakePart part; 0090 0091 const QStringList types = helper.type.split(QLatin1Char(':')); 0092 Q_ASSERT(types.count() == 2); 0093 part.setPartType(PartType(types[1], types[0])); 0094 part.setData(helper.data); 0095 part.setDatasize(helper.size); 0096 part.setStorage(helper.storage); 0097 part.setVersion(helper.version); 0098 parts << part; 0099 } 0100 } 0101 0102 void updateFlags(QList<Flag> &flags, const QStringList &updatedFlags) 0103 { 0104 flags.clear(); 0105 for (const QString &flagName : updatedFlags) { 0106 Flag flag; 0107 flag.setName(flagName); 0108 flags << flag; 0109 } 0110 } 0111 0112 struct TagHelper { 0113 TagHelper(const QString &tagType_, const QString &gid_, const QString &remoteId_ = QString()) 0114 : tagType(tagType_) 0115 , gid(gid_) 0116 , remoteId(remoteId_) 0117 { 0118 } 0119 QString tagType; 0120 QString gid; 0121 QString remoteId; 0122 }; 0123 void updateTags(QList<FakeTag> &tags, const std::vector<TagHelper> &updatedTags) 0124 { 0125 tags.clear(); 0126 for (const TagHelper &helper : updatedTags) { 0127 FakeTag tag; 0128 0129 TagType tagType; 0130 tagType.setName(helper.tagType); 0131 0132 tag.setTagType(tagType); 0133 tag.setGid(helper.gid); 0134 tag.setRemoteId(helper.remoteId); 0135 tags << tag; 0136 } 0137 } 0138 0139 Protocol::CreateItemCommandPtr createCommand(const PimItem &pimItem, const QDateTime &dt, const QSet<QByteArray> &parts, qint64 overrideSize = -1) 0140 { 0141 const qint64 size = overrideSize > -1 ? overrideSize : pimItem.size(); 0142 0143 auto cmd = Protocol::CreateItemCommandPtr::create(); 0144 cmd->setCollection(Scope(pimItem.collectionId())); 0145 cmd->setItemSize(size); 0146 cmd->setRemoteId(pimItem.remoteId()); 0147 cmd->setRemoteRevision(pimItem.remoteRevision()); 0148 cmd->setMimeType(pimItem.mimeType().name()); 0149 cmd->setGid(pimItem.gid()); 0150 cmd->setDateTime(dt); 0151 cmd->setParts(parts); 0152 0153 return cmd; 0154 } 0155 0156 Protocol::FetchItemsResponsePtr createResponse(qint64 expectedId, 0157 const PimItem &pimItem, 0158 const QDateTime &datetime, 0159 const QList<Protocol::StreamPayloadResponse> &parts, 0160 qint64 overrideSize = -1) 0161 { 0162 const qint64 size = overrideSize > -1 ? overrideSize : pimItem.size(); 0163 0164 auto resp = Protocol::FetchItemsResponsePtr::create(expectedId); 0165 resp->setParentId(pimItem.collectionId()); 0166 resp->setSize(size); 0167 resp->setRemoteId(pimItem.remoteId()); 0168 resp->setRemoteRevision(pimItem.remoteRevision()); 0169 resp->setMimeType(pimItem.mimeType().name()); 0170 resp->setGid(pimItem.gid()); 0171 resp->setMTime(datetime); 0172 resp->setParts(parts); 0173 resp->setAncestors({Protocol::Ancestor(4, QLatin1StringView("ColC"))}); 0174 0175 return resp; 0176 } 0177 0178 TestScenario errorResponse(const QString &errorMsg) 0179 { 0180 auto response = Protocol::CreateItemResponsePtr::create(); 0181 response->setError(1, errorMsg); 0182 return TestScenario::create(5, TestScenario::ServerCmd, response); 0183 } 0184 0185 private Q_SLOTS: 0186 void testItemCreate_data() 0187 { 0188 using Notifications = QList<Protocol::ItemChangeNotificationPtr>; 0189 0190 QTest::addColumn<TestScenario::List>("scenarios"); 0191 QTest::addColumn<Notifications>("notifications"); 0192 QTest::addColumn<PimItem>("pimItem"); 0193 QTest::addColumn<QList<FakePart>>("parts"); 0194 QTest::addColumn<QList<Flag>>("flags"); 0195 QTest::addColumn<QList<FakeTag>>("tags"); 0196 QTest::addColumn<qint64>("uidnext"); 0197 QTest::addColumn<QDateTime>("datetime"); 0198 QTest::addColumn<bool>("expectFail"); 0199 0200 TestScenario::List scenarios; 0201 auto notification = Protocol::ItemChangeNotificationPtr::create(); 0202 qint64 uidnext = 0; 0203 QDateTime datetime(QDate(2014, 05, 12), QTime(14, 46, 00), QTimeZone::UTC); 0204 PimItem pimItem; 0205 QList<FakePart> parts; 0206 QList<Flag> flags; 0207 QList<FakeTag> tags; 0208 0209 pimItem.setCollectionId(4); 0210 pimItem.setSize(10); 0211 pimItem.setRemoteId(QStringLiteral("TEST-1")); 0212 pimItem.setRemoteRevision(QStringLiteral("1")); 0213 pimItem.setGid(QStringLiteral("TEST-1")); 0214 pimItem.setMimeType(MimeType::retrieveByName(QStringLiteral("application/octet-stream"))); 0215 pimItem.setDatetime(datetime); 0216 updateParts(parts, {{QLatin1StringView("PLD:DATA"), "0123456789", 10}}); 0217 notification->setOperation(Protocol::ItemChangeNotification::Add); 0218 notification->setParentCollection(4); 0219 notification->setResource("akonadi_fake_resource_0"); 0220 Protocol::FetchItemsResponse item; 0221 item.setId(-1); 0222 item.setRemoteId(QStringLiteral("TEST-1")); 0223 item.setRemoteRevision(QStringLiteral("1")); 0224 item.setMimeType(QStringLiteral("application/octet-stream")); 0225 notification->setItems({std::move(item)}); 0226 notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0227 uidnext = 13; 0228 scenarios 0229 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0230 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0231 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 10))) 0232 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0233 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "0123456789")) 0234 << TestScenario::create(5, 0235 TestScenario::ServerCmd, 0236 createResponse(uidnext, 0237 pimItem, 0238 datetime, 0239 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 10), "0123456789")})) 0240 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0241 QTest::newRow("single-part") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0242 0243 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0244 updatePimItem(pimItem, QStringLiteral("TEST-2"), 20); 0245 updateParts(parts, {{QLatin1StringView("PLD:DATA"), "Random Data", 11}, {QLatin1StringView("PLD:PLDTEST"), "Test Data", 9}}); 0246 updateNotifcationEntity(notification, pimItem); 0247 ++uidnext; 0248 scenarios.clear(); 0249 scenarios 0250 << FakeAkonadiServer::loginScenario() 0251 << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA", "PLD:PLDTEST"})) 0252 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0253 << TestScenario::create(5, 0254 TestScenario::ClientCmd, 0255 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 11, 0))) 0256 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0257 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "Random Data")) 0258 << TestScenario::create(5, 0259 TestScenario::ServerCmd, 0260 Protocol::StreamPayloadCommandPtr::create("PLD:PLDTEST", Protocol::StreamPayloadCommand::MetaData)) 0261 << TestScenario::create(5, 0262 TestScenario::ClientCmd, 0263 Protocol::StreamPayloadResponsePtr::create("PLD:PLDTEST", Protocol::PartMetaData("PLD:PLDTEST", 9, 0))) 0264 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:PLDTEST", Protocol::StreamPayloadCommand::Data)) 0265 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:PLDTEST", "Test Data")) 0266 << TestScenario::create(5, 0267 TestScenario::ServerCmd, 0268 createResponse(uidnext, 0269 pimItem, 0270 datetime, 0271 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 11), "Random Data"), 0272 Protocol::StreamPayloadResponse("PLD:PLDTEST", Protocol::PartMetaData("PLD:PLDTEST", 9), "Test Data")})) 0273 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0274 QTest::newRow("multi-part") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0275 0276 TestScenario inScenario; 0277 TestScenario outScenario; 0278 { 0279 auto cmd = Protocol::CreateItemCommandPtr::create(); 0280 cmd->setCollection(Scope(100)); 0281 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0282 } 0283 scenarios.clear(); 0284 scenarios << FakeAkonadiServer::loginScenario() << inScenario << errorResponse(QStringLiteral("Invalid parent collection")); 0285 QTest::newRow("invalid collection") << scenarios << Notifications{} << PimItem() << QList<FakePart>() << QList<Flag>() << QList<FakeTag>() << -1ll 0286 << QDateTime() << true; 0287 0288 { 0289 auto cmd = Protocol::CreateItemCommandPtr::create(); 0290 cmd->setCollection(Scope(6)); 0291 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0292 } 0293 scenarios.clear(); 0294 scenarios << FakeAkonadiServer::loginScenario() << inScenario << errorResponse(QStringLiteral("Cannot append item into virtual collection")); 0295 QTest::newRow("virtual collection") << scenarios << Notifications{} << PimItem() << QList<FakePart>() << QList<Flag>() << QList<FakeTag>() << -1ll 0296 << QDateTime() << true; 0297 0298 updatePimItem(pimItem, QStringLiteral("TEST-3"), 5); 0299 updateParts(parts, {{QLatin1StringView("PLD:DATA"), "12345", 5}}); 0300 updateNotifcationEntity(notification, pimItem); 0301 ++uidnext; 0302 scenarios.clear(); 0303 scenarios 0304 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"}, 1)) 0305 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0306 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) 0307 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0308 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "12345")) 0309 << TestScenario::create( 0310 5, 0311 TestScenario::ServerCmd, 0312 createResponse(uidnext, pimItem, datetime, {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5), "12345")})) 0313 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0314 QTest::newRow("mismatch item sizes (smaller)") 0315 << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0316 0317 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0318 updatePimItem(pimItem, QStringLiteral("TEST-4"), 10); 0319 updateNotifcationEntity(notification, pimItem); 0320 ++uidnext; 0321 scenarios.clear(); 0322 scenarios 0323 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"}, 10)) 0324 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0325 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) 0326 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0327 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "12345")) 0328 << TestScenario::create(5, 0329 TestScenario::ServerCmd, 0330 createResponse(uidnext, 0331 pimItem, 0332 datetime, 0333 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5), "12345")}, 0334 10)) 0335 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0336 QTest::newRow("mismatch item sizes (bigger)") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime 0337 << false; 0338 0339 scenarios.clear(); 0340 scenarios 0341 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0342 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0343 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) 0344 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0345 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "123")) 0346 << errorResponse(QStringLiteral("Payload size mismatch")); 0347 QTest::newRow("incomplete part data") << scenarios << Notifications{} << PimItem() << QList<FakePart>() << QList<Flag>() << QList<FakeTag>() << -1ll 0348 << QDateTime() << true; 0349 0350 scenarios.clear(); 0351 scenarios 0352 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0353 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0354 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) 0355 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0356 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "1234567890")) 0357 << errorResponse(QStringLiteral("Payload size mismatch")); 0358 QTest::newRow("part data larger than advertised") 0359 << scenarios << Notifications{} << PimItem() << QList<FakePart>() << QList<Flag>() << QList<FakeTag>() << -1ll << QDateTime() << true; 0360 0361 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0362 updatePimItem(pimItem, QStringLiteral("TEST-5"), 0); 0363 updateParts(parts, {{QLatin1StringView("PLD:DATA"), QByteArray(), 0}}); 0364 updateNotifcationEntity(notification, pimItem); 0365 ++uidnext; 0366 scenarios.clear(); 0367 scenarios 0368 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0369 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0370 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 0))) 0371 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0372 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", QByteArray())) 0373 << TestScenario::create(5, 0374 TestScenario::ServerCmd, 0375 createResponse(uidnext, 0376 pimItem, 0377 datetime, 0378 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 0), QByteArray())})) 0379 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0380 QTest::newRow("empty payload part") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0381 0382 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0383 updatePimItem(pimItem, QStringLiteral("TEST-8"), 1); 0384 updateParts(parts, {{QLatin1StringView("PLD:DATA"), QByteArray("\0", 1), 1}}); 0385 updateNotifcationEntity(notification, pimItem); 0386 ++uidnext; 0387 scenarios.clear(); 0388 scenarios 0389 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0390 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0391 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 1))) 0392 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0393 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", QByteArray("\0", 1))) 0394 << TestScenario::create(5, 0395 TestScenario::ServerCmd, 0396 createResponse(uidnext, 0397 pimItem, 0398 datetime, 0399 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 1), QByteArray("\0", 1))})) 0400 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0401 QTest::newRow("part data will null character") 0402 << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0403 0404 const QString utf8String = QStringLiteral("äöüß@€µøđ¢©®"); 0405 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0406 updatePimItem(pimItem, QStringLiteral("TEST-9"), utf8String.toUtf8().size()); 0407 updateParts(parts, {{QLatin1StringView("PLD:DATA"), utf8String.toUtf8(), utf8String.toUtf8().size()}}); 0408 updateNotifcationEntity(notification, pimItem); 0409 ++uidnext; 0410 scenarios.clear(); 0411 scenarios 0412 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0413 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0414 << TestScenario::create(5, 0415 TestScenario::ClientCmd, 0416 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) 0417 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0418 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", utf8String.toUtf8())) 0419 << TestScenario::create( 0420 5, 0421 TestScenario::ServerCmd, 0422 createResponse( 0423 uidnext, 0424 pimItem, 0425 datetime, 0426 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", utf8String.toUtf8().size()), utf8String.toUtf8())})) 0427 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0428 QTest::newRow("utf8 part data") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0429 0430 const QByteArray hugeData = QByteArray("a").repeated(1 << 20); 0431 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0432 updatePimItem(pimItem, QStringLiteral("TEST-10"), 1 << 20); 0433 updateParts(parts, {{QLatin1StringView("PLD:DATA"), hugeData, 1 << 20}}); 0434 updateNotifcationEntity(notification, pimItem); 0435 ++uidnext; 0436 scenarios.clear(); 0437 scenarios 0438 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0439 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0440 << TestScenario::create(5, 0441 TestScenario::ClientCmd, 0442 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) 0443 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0444 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", hugeData)) 0445 << TestScenario::create( 0446 5, 0447 TestScenario::ServerCmd, 0448 createResponse(uidnext, 0449 pimItem, 0450 datetime, 0451 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()), hugeData)})) 0452 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0453 QTest::newRow("huge part data") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0454 0455 const QByteArray dataWithNewLines = "Bernard, Bernard, Bernard, Bernard, look, look Bernard!\nWHAT!!!!!!!\nI'm a prostitute robot from the future!"; 0456 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0457 updatePimItem(pimItem, QStringLiteral("TEST-11"), dataWithNewLines.size()); 0458 updateParts(parts, {{QLatin1StringView("PLD:DATA"), dataWithNewLines, dataWithNewLines.size()}}); 0459 updateNotifcationEntity(notification, pimItem); 0460 ++uidnext; 0461 scenarios.clear(); 0462 scenarios 0463 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0464 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0465 << TestScenario::create(5, 0466 TestScenario::ClientCmd, 0467 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) 0468 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0469 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", dataWithNewLines)) 0470 << TestScenario::create( 0471 5, 0472 TestScenario::ServerCmd, 0473 createResponse(uidnext, 0474 pimItem, 0475 datetime, 0476 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", dataWithNewLines.size()), dataWithNewLines)})) 0477 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0478 QTest::newRow("data with newlines") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0479 0480 const QByteArray lotsOfNewlines = QByteArray("\n").repeated(1 << 20); 0481 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0482 updatePimItem(pimItem, QStringLiteral("TEST-12"), lotsOfNewlines.size()); 0483 updateParts(parts, {{QLatin1StringView("PLD:DATA"), lotsOfNewlines, lotsOfNewlines.size()}}); 0484 updateNotifcationEntity(notification, pimItem); 0485 ++uidnext; 0486 scenarios.clear(); 0487 scenarios 0488 << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:DATA"})) 0489 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0490 << TestScenario::create(5, 0491 TestScenario::ClientCmd, 0492 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) 0493 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0494 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", lotsOfNewlines)) 0495 << TestScenario::create( 0496 5, 0497 TestScenario::ServerCmd, 0498 createResponse(uidnext, 0499 pimItem, 0500 datetime, 0501 {Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()), lotsOfNewlines)})) 0502 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0503 QTest::newRow("data with lots of newlines") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime 0504 << false; 0505 0506 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0507 updatePimItem(pimItem, QStringLiteral("TEST-13"), 20); 0508 updateParts(parts, {{QLatin1StringView("PLD:NEWPARTTYPE1"), "0123456789", 10}, {QLatin1StringView("PLD:NEWPARTTYPE2"), "9876543210", 10}}); 0509 updateNotifcationEntity(notification, pimItem); 0510 ++uidnext; 0511 scenarios.clear(); 0512 scenarios << FakeAkonadiServer::loginScenario() 0513 << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, {"PLD:NEWPARTTYPE1", "PLD:NEWPARTTYPE2"})) 0514 << TestScenario::create(5, 0515 TestScenario::ServerCmd, 0516 Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE1", Protocol::StreamPayloadCommand::MetaData)) 0517 << TestScenario::create(5, 0518 TestScenario::ClientCmd, 0519 Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE1", Protocol::PartMetaData("PLD:NEWPARTTYPE1", 10))) 0520 << TestScenario::create(5, 0521 TestScenario::ServerCmd, 0522 Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE1", Protocol::StreamPayloadCommand::Data)) 0523 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE2", "0123456789")) 0524 << TestScenario::create(5, 0525 TestScenario::ServerCmd, 0526 Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE2", Protocol::StreamPayloadCommand::MetaData)) 0527 << TestScenario::create(5, 0528 TestScenario::ClientCmd, 0529 Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE2", Protocol::PartMetaData("PLD:NEWPARTTYPE2", 10))) 0530 << TestScenario::create(5, 0531 TestScenario::ServerCmd, 0532 Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE2", Protocol::StreamPayloadCommand::Data)) 0533 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE2", "9876543210")) 0534 << TestScenario::create( 0535 5, 0536 TestScenario::ServerCmd, 0537 createResponse(uidnext, 0538 pimItem, 0539 datetime, 0540 {Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE1", Protocol::PartMetaData("PLD:NEWPARTTYPE1", 10), "0123456789"), 0541 Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE2", Protocol::PartMetaData("PLD:NEWPARTTYPE2", 10), "9876543210")})) 0542 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0543 QTest::newRow("non-existent part types") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime 0544 << false; 0545 0546 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0547 updatePimItem(pimItem, QStringLiteral("TEST-14"), 0); 0548 updateParts(parts, {}); 0549 updateFlags(flags, QStringList() << QStringLiteral("\\SEEN") << QStringLiteral("\\RANDOM")); 0550 updateNotifcationEntity(notification, pimItem); 0551 ++uidnext; 0552 { 0553 auto cmd = createCommand(pimItem, datetime, {}); 0554 cmd->setFlags({"\\SEEN", "\\RANDOM"}); 0555 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0556 0557 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0558 rsp->setFlags({"\\SEEN", "\\RANDOM"}); 0559 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0560 } 0561 scenarios.clear(); 0562 scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario 0563 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0564 QTest::newRow("item with flags") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0565 0566 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0567 updatePimItem(pimItem, QStringLiteral("TEST-15"), 0); 0568 updateFlags(flags, {}); 0569 updateTags(tags, {{QLatin1StringView("PLAIN"), QLatin1StringView("TAG-1")}, {QLatin1StringView("PLAIN"), QLatin1StringView("TAG-2")}}); 0570 updateNotifcationEntity(notification, pimItem); 0571 ++uidnext; 0572 { 0573 auto cmd = createCommand(pimItem, datetime, {}); 0574 cmd->setTags(Scope(Scope::Gid, {QLatin1StringView("TAG-1"), QLatin1StringView("TAG-2")})); 0575 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0576 0577 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0578 rsp->setTags({Protocol::FetchTagsResponse(2, "TAG-1", "PLAIN"), Protocol::FetchTagsResponse(3, "TAG-2", "PLAIN")}); 0579 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0580 } 0581 scenarios.clear(); 0582 scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario 0583 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0584 QTest::newRow("item with non-existent tags (GID)") 0585 << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0586 0587 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0588 updatePimItem(pimItem, QStringLiteral("TEST-16"), 0); 0589 updateTags(tags, {{QLatin1StringView("PLAIN"), QLatin1StringView("TAG-3")}, {QLatin1StringView("PLAIN"), QLatin1StringView("TAG-4")}}); 0590 updateNotifcationEntity(notification, pimItem); 0591 ++uidnext; 0592 { 0593 auto cmd = createCommand(pimItem, datetime, {}); 0594 cmd->setTags(Scope(Scope::Rid, {QLatin1StringView("TAG-3"), QLatin1StringView("TAG-4")})); 0595 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0596 0597 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0598 rsp->setTags({Protocol::FetchTagsResponse(4, "TAG-3", "PLAIN"), Protocol::FetchTagsResponse(5, "TAG-4", "PLAIN")}); 0599 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0600 } 0601 scenarios.clear(); 0602 scenarios << FakeAkonadiServer::loginScenario() << FakeAkonadiServer::selectResourceScenario(QStringLiteral("akonadi_fake_resource_0")) << inScenario 0603 << outScenario << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0604 QTest::newRow("item with non-existent tags (RID)") 0605 << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0606 0607 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0608 updatePimItem(pimItem, QStringLiteral("TEST-17"), 0); 0609 updateNotifcationEntity(notification, pimItem); 0610 updateTags(tags, {{QLatin1StringView("PLAIN"), QLatin1StringView("TAG-1")}, {QLatin1StringView("PLAIN"), QLatin1StringView("TAG-2")}}); 0611 ++uidnext; 0612 { 0613 auto cmd = createCommand(pimItem, datetime, {}); 0614 cmd->setTags(Scope(Scope::Rid, {QLatin1StringView("TAG-1"), QLatin1StringView("TAG-2")})); 0615 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0616 0617 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0618 rsp->setTags({Protocol::FetchTagsResponse(2, "TAG-1", "PLAIN"), Protocol::FetchTagsResponse(3, "TAG-2", "PLAIN")}); 0619 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0620 } 0621 scenarios.clear(); 0622 scenarios << FakeAkonadiServer::loginScenario() << FakeAkonadiServer::selectResourceScenario(QStringLiteral("akonadi_fake_resource_0")) << inScenario 0623 << outScenario << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0624 QTest::newRow("item with existing tags (RID)") 0625 << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0626 0627 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0628 updatePimItem(pimItem, QStringLiteral("TEST-18"), 0); 0629 updateNotifcationEntity(notification, pimItem); 0630 updateTags(tags, {{QLatin1StringView("PLAIN"), QLatin1StringView("TAG-3")}, {QLatin1StringView("PLAIN"), QLatin1StringView("TAG-4")}}); 0631 ++uidnext; 0632 { 0633 auto cmd = createCommand(pimItem, datetime, {}); 0634 cmd->setTags(Scope(Scope::Gid, {QLatin1StringView("TAG-3"), QLatin1StringView("TAG-4")})); 0635 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0636 0637 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0638 rsp->setTags({Protocol::FetchTagsResponse(4, "TAG-3", "PLAIN"), Protocol::FetchTagsResponse(5, "TAG-4", "PLAIN")}); 0639 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0640 } 0641 scenarios.clear(); 0642 scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario 0643 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0644 QTest::newRow("item with existing tags (GID)") 0645 << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0646 0647 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0648 updatePimItem(pimItem, QStringLiteral("TEST-19"), 0); 0649 updateFlags(flags, QStringList() << QStringLiteral("\\SEEN") << QStringLiteral("$FLAG")); 0650 updateTags(tags, {{QLatin1StringView("PLAIN"), QLatin1StringView("TAG-1")}, {QLatin1StringView("PLAIN"), QLatin1StringView("TAG-2")}}); 0651 updateNotifcationEntity(notification, pimItem); 0652 ++uidnext; 0653 { 0654 auto cmd = createCommand(pimItem, datetime, {}); 0655 cmd->setTags(Scope(Scope::Gid, {QLatin1StringView("TAG-1"), QLatin1StringView("TAG-2")})); 0656 cmd->setFlags({"\\SEEN", "$FLAG"}); 0657 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0658 0659 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0660 rsp->setTags({Protocol::FetchTagsResponse(2, "TAG-1", "PLAIN"), Protocol::FetchTagsResponse(3, "TAG-2", "PLAIN")}); 0661 rsp->setFlags({"\\SEEN", "$FLAG"}); 0662 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0663 } 0664 scenarios.clear(); 0665 scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario 0666 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0667 QTest::newRow("item with flags and tags") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime 0668 << false; 0669 0670 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0671 updatePimItem(pimItem, QStringLiteral("TEST-20"), 0); 0672 updateFlags(flags, {}); 0673 updateTags(tags, {{QLatin1StringView("PLAIN"), utf8String}}); 0674 updateNotifcationEntity(notification, pimItem); 0675 ++uidnext; 0676 { 0677 auto cmd = createCommand(pimItem, datetime, {}); 0678 cmd->setTags(Scope(Scope::Gid, {utf8String})); 0679 inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); 0680 0681 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0682 rsp->setTags({Protocol::FetchTagsResponse(6, utf8String.toUtf8(), "PLAIN")}); 0683 outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); 0684 } 0685 scenarios.clear(); 0686 scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario 0687 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0688 QTest::newRow("item with UTF-8 tag") << scenarios << Notifications{notification} << pimItem << parts << flags << tags << uidnext << datetime << false; 0689 0690 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0691 updatePimItem(pimItem, QStringLiteral("TEST-21"), 0); 0692 updateFlags(flags, {}); 0693 updateTags(tags, {}); 0694 pimItem.setGid(QStringLiteral("GID-21")); 0695 updateNotifcationEntity(notification, pimItem); 0696 scenarios = FakeAkonadiServer::loginScenario(); 0697 // Create a normal item with RID 0698 { 0699 ++uidnext; 0700 auto cmd = createCommand(pimItem, datetime, {}); 0701 scenarios << TestScenario::create(5, TestScenario::ClientCmd, cmd); 0702 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0703 scenarios << TestScenario::create(5, TestScenario::ServerCmd, rsp) 0704 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0705 } 0706 // Create the same item again (no merging, so it will just be created) 0707 { 0708 ++uidnext; 0709 auto cmd = createCommand(pimItem, datetime, {}); 0710 scenarios << TestScenario::create(6, TestScenario::ClientCmd, cmd); 0711 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0712 scenarios << TestScenario::create(6, TestScenario::ServerCmd, rsp) 0713 << TestScenario::create(6, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0714 } 0715 // Now try to create the item once again, but in merge mode, we should fail now 0716 { 0717 ++uidnext; 0718 auto cmd = createCommand(pimItem, datetime, {}); 0719 cmd->setMergeModes(Protocol::CreateItemCommand::RemoteID); 0720 scenarios << TestScenario::create(7, TestScenario::ClientCmd, cmd); 0721 auto rsp = Protocol::CreateItemResponsePtr::create(); 0722 rsp->setError(1, QStringLiteral("Multiple merge candidates")); 0723 scenarios << TestScenario::create(7, TestScenario::ServerCmd, rsp); 0724 } 0725 Notifications notifications = {notification, Protocol::ItemChangeNotificationPtr::create(*notification)}; 0726 QTest::newRow("multiple merge candidates (RID)") << scenarios << notifications << pimItem << parts << flags << tags << uidnext << datetime << true; 0727 0728 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0729 updatePimItem(pimItem, QStringLiteral("TEST-22"), 0); 0730 pimItem.setGid(QStringLiteral("GID-22")); 0731 updateNotifcationEntity(notification, pimItem); 0732 scenarios = FakeAkonadiServer::loginScenario(); 0733 // Create a normal item with GID 0734 { 0735 // Don't increase uidnext, we will reuse the one from previous test, 0736 // since that did not actually create a new Item 0737 auto cmd = createCommand(pimItem, datetime, {}); 0738 scenarios << TestScenario::create(5, TestScenario::ClientCmd, cmd); 0739 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0740 scenarios << TestScenario::create(5, TestScenario::ServerCmd, rsp) 0741 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0742 } 0743 // Create the same item again (no merging, so it will just be created) 0744 { 0745 ++uidnext; 0746 auto cmd = createCommand(pimItem, datetime, {}); 0747 scenarios << TestScenario::create(6, TestScenario::ClientCmd, cmd); 0748 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0749 scenarios << TestScenario::create(6, TestScenario::ServerCmd, rsp) 0750 << TestScenario::create(6, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0751 } 0752 // Now try to create the item once again, but in merge mode, we should fail now 0753 { 0754 ++uidnext; 0755 auto cmd = createCommand(pimItem, datetime, {}); 0756 cmd->setMergeModes(Protocol::CreateItemCommand::GID); 0757 scenarios << TestScenario::create(7, TestScenario::ClientCmd, cmd); 0758 auto rsp = Protocol::CreateItemResponsePtr::create(); 0759 rsp->setError(1, QStringLiteral("Multiple merge candidates")); 0760 scenarios << TestScenario::create(7, TestScenario::ServerCmd, rsp); 0761 } 0762 notifications = {notification, Protocol::ItemChangeNotificationPtr::create(*notification)}; 0763 QTest::newRow("multiple merge candidates (GID)") << scenarios << notifications << pimItem << parts << flags << tags << uidnext << datetime << true; 0764 0765 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0766 updatePimItem(pimItem, QStringLiteral("TEST-23"), 0); 0767 pimItem.setGid(QString()); 0768 updateNotifcationEntity(notification, pimItem); 0769 scenarios = FakeAkonadiServer::loginScenario(); 0770 // Create a normal item with RID, but with empty GID 0771 { 0772 // Don't increase uidnext, we will reuse the one from previous test, 0773 // since that did not actually create a new Item 0774 auto cmd = createCommand(pimItem, datetime, {}); 0775 scenarios << TestScenario::create(5, TestScenario::ClientCmd, cmd); 0776 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0777 scenarios << TestScenario::create(5, TestScenario::ServerCmd, rsp) 0778 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0779 } 0780 // Merge by GID - should not create a new Item but actually merge by RID, 0781 // since an item with matching RID but empty GID exists 0782 { 0783 ++uidnext; 0784 pimItem.setGid(QStringLiteral("GID-23")); 0785 auto cmd = createCommand(pimItem, datetime, {}); 0786 cmd->setMergeModes(Protocol::CreateItemCommand::GID); 0787 scenarios << TestScenario::create(6, TestScenario::ClientCmd, cmd); 0788 auto rsp = createResponse(uidnext, pimItem, datetime, {}); 0789 scenarios << TestScenario::create(6, TestScenario::ServerCmd, rsp) 0790 << TestScenario::create(6, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); 0791 } 0792 notifications = {notification, Protocol::ItemChangeNotificationPtr::create(*notification)}; 0793 QTest::newRow("merge into empty GID if RID matches") << scenarios << notifications << pimItem << parts << flags << tags << uidnext << datetime << false; 0794 } 0795 0796 void testItemCreate() 0797 { 0798 QFETCH(TestScenario::List, scenarios); 0799 QFETCH(QList<Protocol::ItemChangeNotificationPtr>, notifications); 0800 QFETCH(PimItem, pimItem); 0801 QFETCH(QList<FakePart>, parts); 0802 QFETCH(QList<Flag>, flags); 0803 QFETCH(QList<FakeTag>, tags); 0804 QFETCH(qint64, uidnext); 0805 QFETCH(bool, expectFail); 0806 0807 mAkonadi.setScenarios(scenarios); 0808 mAkonadi.runTest(); 0809 0810 auto notificationSpy = mAkonadi.notificationSpy(); 0811 0812 QTRY_COMPARE(notificationSpy->count(), notifications.count()); 0813 for (int i = 0; i < notifications.count(); ++i) { 0814 const auto incomingNtfs = notificationSpy->at(i).first().value<Protocol::ChangeNotificationList>(); 0815 QCOMPARE(incomingNtfs.count(), 1); 0816 const auto itemNotification = incomingNtfs.at(0).staticCast<Protocol::ItemChangeNotification>(); 0817 0818 QVERIFY(AkTest::compareNotifications(itemNotification, notifications.at(i), QFlag(AkTest::NtfAll & ~AkTest::NtfEntities))); 0819 QCOMPARE(itemNotification->items().count(), notifications.at(i)->items().count()); 0820 } 0821 0822 const PimItem actualItem = PimItem::retrieveById(uidnext); 0823 if (expectFail) { 0824 QVERIFY(!actualItem.isValid()); 0825 } else { 0826 QVERIFY(actualItem.isValid()); 0827 QCOMPARE(actualItem.remoteId(), pimItem.remoteId()); 0828 QCOMPARE(actualItem.remoteRevision(), pimItem.remoteRevision()); 0829 QCOMPARE(actualItem.gid(), pimItem.gid()); 0830 QCOMPARE(actualItem.size(), pimItem.size()); 0831 QCOMPARE(actualItem.datetime(), pimItem.datetime()); 0832 QCOMPARE(actualItem.collectionId(), pimItem.collectionId()); 0833 QCOMPARE(actualItem.mimeTypeId(), pimItem.mimeTypeId()); 0834 0835 const auto actualFlags = actualItem.flags() | AkRanges::Actions::toQList; 0836 QCOMPARE(actualFlags.count(), flags.count()); 0837 for (const Flag &flag : std::as_const(flags)) { 0838 const auto actualFlagIter = std::find_if(actualFlags.constBegin(), actualFlags.constEnd(), [flag](Flag const &actualFlag) { 0839 return flag.name() == actualFlag.name(); 0840 }); 0841 QVERIFY(actualFlagIter != actualFlags.constEnd()); 0842 const Flag actualFlag = *actualFlagIter; 0843 QVERIFY(actualFlag.isValid()); 0844 } 0845 0846 const auto actualTags = actualItem.tags() | AkRanges::Actions::toQList; 0847 QCOMPARE(actualTags.count(), tags.count()); 0848 for (const FakeTag &tag : std::as_const(tags)) { 0849 const auto actualTagIter = std::find_if(actualTags.constBegin(), actualTags.constEnd(), [tag](Tag const &actualTag) { 0850 return tag.gid() == actualTag.gid(); 0851 }); 0852 0853 QVERIFY(actualTagIter != actualTags.constEnd()); 0854 const Tag actualTag = *actualTagIter; 0855 QVERIFY(actualTag.isValid()); 0856 QCOMPARE(actualTag.tagType().name(), tag.tagType().name()); 0857 QCOMPARE(actualTag.gid(), tag.gid()); 0858 if (!tag.remoteId().isEmpty()) { 0859 SelectQueryBuilder<TagRemoteIdResourceRelation> qb; 0860 qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdFullColumnName(), Query::Equals, QLatin1StringView("akonadi_fake_resource_0")); 0861 qb.addValueCondition(TagRemoteIdResourceRelation::tagIdColumn(), Query::Equals, actualTag.id()); 0862 QVERIFY(qb.exec()); 0863 QCOMPARE(qb.result().size(), 1); 0864 QCOMPARE(qb.result().at(0).remoteId(), tag.remoteId()); 0865 } 0866 } 0867 0868 const auto actualParts = actualItem.parts() | AkRanges::Actions::toQList; 0869 QCOMPARE(actualParts.count(), parts.count()); 0870 for (const FakePart &part : std::as_const(parts)) { 0871 const auto actualPartIter = std::find_if(actualParts.constBegin(), actualParts.constEnd(), [part](Part const &actualPart) { 0872 return part.partType().ns() == actualPart.partType().ns() && part.partType().name() == actualPart.partType().name(); 0873 }); 0874 0875 QVERIFY(actualPartIter != actualParts.constEnd()); 0876 const Part actualPart = *actualPartIter; 0877 QVERIFY(actualPart.isValid()); 0878 QCOMPARE(QString::fromUtf8(actualPart.data()), QString::fromUtf8(part.data())); 0879 QCOMPARE(actualPart.data(), part.data()); 0880 QCOMPARE(actualPart.datasize(), part.datasize()); 0881 QCOMPARE(actualPart.storage(), part.storage()); 0882 } 0883 } 0884 } 0885 }; 0886 0887 AKTEST_FAKESERVER_MAIN(ItemCreateHandlerTest) 0888 0889 #include "itemcreatehandlertest.moc"