File indexing completed on 2024-05-12 05:10:39
0001 /* 0002 SPDX-FileCopyrightText: 2010-2011 Sérgio Martins <iamsergio@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "../src/incidencechanger.h" 0008 0009 #include <Akonadi/Collection> 0010 #include <Akonadi/CollectionFetchJob> 0011 #include <Akonadi/CollectionFetchScope> 0012 #include <akonadi/qtest_akonadi.h> 0013 0014 #include <Akonadi/Item> 0015 #include <Akonadi/ItemCreateJob> 0016 #include <Akonadi/ItemDeleteJob> 0017 #include <Akonadi/ItemFetchJob> 0018 #include <Akonadi/ItemFetchScope> 0019 0020 #include <KCalendarCore/Event> 0021 0022 #include <QBitArray> 0023 0024 using namespace Akonadi; 0025 using namespace KCalendarCore; 0026 0027 Q_DECLARE_METATYPE(QList<Akonadi::IncidenceChanger::ChangeType>) 0028 Q_DECLARE_METATYPE(QList<bool>) 0029 Q_DECLARE_METATYPE(QList<Akonadi::Collection::Right>) 0030 Q_DECLARE_METATYPE(QList<Akonadi::Collection::Rights>) 0031 Q_DECLARE_METATYPE(QList<Akonadi::IncidenceChanger::ResultCode>) 0032 Q_DECLARE_METATYPE(KCalendarCore::RecurrenceRule::PeriodType) 0033 QString s_ourEmail = QStringLiteral("unittests@dev.nul"); // change also in kdepimlibs/akonadi/calendar/tests/unittestenv/kdehome/share/config 0034 QString s_outEmail2 = QStringLiteral("identity2@kde.org"); 0035 0036 static Akonadi::Item item() 0037 { 0038 Item item; 0039 Incidence::Ptr incidence = Incidence::Ptr(new Event()); 0040 incidence->setSummary(QStringLiteral("random summary")); 0041 item.setMimeType(incidence->mimeType()); 0042 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0043 return item; 0044 } 0045 0046 static Akonadi::Item createItem(const Akonadi::Collection &collection) 0047 { 0048 Item i = item(); 0049 auto createJob = new ItemCreateJob(i, collection); 0050 0051 createJob->exec(); 0052 return createJob->item(); 0053 } 0054 0055 class IncidenceChangerTest : public QObject 0056 { 0057 Q_OBJECT 0058 Collection mCollection; 0059 0060 QHash<int, IncidenceChanger::ResultCode> mExpectedResultByChangeId; 0061 IncidenceChanger *mChanger = nullptr; 0062 0063 int mIncidencesToDelete; 0064 int mIncidencesToAdd; 0065 int mIncidencesToModify; 0066 0067 QHash<int, Akonadi::Item::Id> mItemIdByChangeId; 0068 QHash<QString, Akonadi::Item::Id> mItemIdByUid; 0069 int mChangeToWaitFor; 0070 bool mPermissionsOrRollback; 0071 bool mDiscardedEqualsSuccess; 0072 Akonadi::Item mLastItemCreated; 0073 0074 private Q_SLOTS: 0075 void initTestCase() 0076 { 0077 AkonadiTest::checkTestIsIsolated(); 0078 0079 mIncidencesToDelete = 0; 0080 mIncidencesToAdd = 0; 0081 mIncidencesToModify = 0; 0082 mPermissionsOrRollback = false; 0083 mDiscardedEqualsSuccess = false; 0084 0085 mChangeToWaitFor = -1; 0086 // Control::start(); //TODO: uncomment when using testrunner 0087 qRegisterMetaType<Akonadi::Item>("Akonadi::Item"); 0088 qRegisterMetaType<QList<Akonadi::IncidenceChanger::ChangeType>>("QList<Akonadi::IncidenceChanger::ChangeType>"); 0089 auto job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); 0090 // Get list of collections 0091 job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.event")); 0092 AKVERIFYEXEC(job); 0093 0094 // Find our collection 0095 Collection::List collections = job->collections(); 0096 QVERIFY(!collections.isEmpty()); 0097 mCollection = collections.first(); 0098 mCollection.setRights(Collection::Rights(Collection::AllRights)); 0099 0100 QVERIFY(mCollection.isValid()); 0101 QVERIFY((mCollection.rights() & Akonadi::Collection::CanCreateItem)); 0102 0103 mChanger = new IncidenceChanger(this); 0104 mChanger->setShowDialogsOnError(false); 0105 0106 connect(mChanger, &IncidenceChanger::createFinished, this, &IncidenceChangerTest::createFinished); 0107 0108 connect(mChanger, &IncidenceChanger::deleteFinished, this, &IncidenceChangerTest::deleteFinished); 0109 0110 connect(mChanger, &IncidenceChanger::modifyFinished, this, &IncidenceChangerTest::modifyFinished); 0111 } 0112 0113 void testCreating_data() 0114 { 0115 QTest::addColumn<bool>("sendInvalidIncidence"); 0116 QTest::addColumn<QString>("uid"); 0117 QTest::addColumn<QString>("summary"); 0118 QTest::addColumn<Akonadi::Collection>("destinationCollection"); 0119 QTest::addColumn<Akonadi::Collection>("defaultCollection"); 0120 QTest::addColumn<bool>("respectsCollectionRights"); 0121 QTest::addColumn<Akonadi::IncidenceChanger::DestinationPolicy>("destinationPolicy"); 0122 QTest::addColumn<bool>("failureExpected"); 0123 QTest::addColumn<Akonadi::IncidenceChanger::ResultCode>("expectedResultCode"); 0124 0125 QTest::newRow("Simple Creation1") << false << "SomeUid1" 0126 << "Summary1" << mCollection << Collection() << true << IncidenceChanger::DestinationPolicyNeverAsk << false 0127 << IncidenceChanger::ResultCodeSuccess; 0128 0129 QTest::newRow("Simple Creation2") << false << "SomeUid2" 0130 << "Summary2" << mCollection << Collection() << true << IncidenceChanger::DestinationPolicyNeverAsk << false 0131 << IncidenceChanger::ResultCodeSuccess; 0132 0133 QTest::newRow("Invalid incidence") << true << "SomeUid3" 0134 << "Summary3" << mCollection << Collection() << true << IncidenceChanger::DestinationPolicyNeverAsk << true; 0135 0136 QTest::newRow("Invalid collection") << false << "SomeUid4" 0137 << "Summary4" << Collection() << Collection() << true << IncidenceChanger::DestinationPolicyNeverAsk << false 0138 << IncidenceChanger::ResultCodeInvalidDefaultCollection; 0139 0140 QTest::newRow("Default collection") << false << "SomeUid5" 0141 << "Summary5" << Collection() << mCollection << true << IncidenceChanger::DestinationPolicyDefault << false 0142 << IncidenceChanger::ResultCodeSuccess; 0143 0144 // In this case, the collection dialog shouldn't be shown, as we only have 1 collection 0145 QTest::newRow("Only one collection") << false << "SomeUid6" 0146 << "Summary6" << Collection() << Collection() << true << IncidenceChanger::DestinationPolicyAsk << false 0147 << IncidenceChanger::ResultCodeSuccess; 0148 0149 Collection collectionWithoutRights = Collection(mCollection.id()); 0150 collectionWithoutRights.setRights(Collection::Rights()); 0151 Q_ASSERT((mCollection.rights() & Akonadi::Collection::CanCreateItem)); 0152 0153 QTest::newRow("No rights") << false << "SomeUid6" 0154 << "Summary6" << Collection() << collectionWithoutRights << true << IncidenceChanger::DestinationPolicyNeverAsk << false 0155 << IncidenceChanger::ResultCodePermissions; 0156 0157 QTest::newRow("No rights but its ok") << false << "SomeUid7" 0158 << "Summary7" << Collection() << collectionWithoutRights << false << IncidenceChanger::DestinationPolicyNeverAsk 0159 << false << IncidenceChanger::ResultCodeSuccess; 0160 } 0161 0162 void testCreating() 0163 { 0164 QFETCH(bool, sendInvalidIncidence); 0165 QFETCH(QString, uid); 0166 QFETCH(QString, summary); 0167 QFETCH(Akonadi::Collection, destinationCollection); 0168 QFETCH(Akonadi::Collection, defaultCollection); 0169 QFETCH(bool, respectsCollectionRights); 0170 QFETCH(Akonadi::IncidenceChanger::DestinationPolicy, destinationPolicy); 0171 QFETCH(bool, failureExpected); 0172 0173 Incidence::Ptr incidence; 0174 0175 if (!sendInvalidIncidence) { 0176 incidence = Incidence::Ptr(new Event()); 0177 incidence->setUid(uid); 0178 incidence->setSummary(summary); 0179 } 0180 mChanger->setRespectsCollectionRights(respectsCollectionRights); 0181 mChanger->setDestinationPolicy(destinationPolicy); 0182 mChanger->setDefaultCollection(defaultCollection); 0183 const int changeId = mChanger->createIncidence(incidence, destinationCollection); 0184 0185 QVERIFY(failureExpected ^ (changeId != -1)); 0186 0187 if (!failureExpected) { 0188 QFETCH(Akonadi::IncidenceChanger::ResultCode, expectedResultCode); 0189 mIncidencesToAdd = 1; 0190 0191 mExpectedResultByChangeId.insert(changeId, expectedResultCode); 0192 waitForSignals(); 0193 0194 if (expectedResultCode == IncidenceChanger::ResultCodeSuccess && !failureExpected) { 0195 Item item; 0196 QVERIFY(mItemIdByChangeId.contains(changeId)); 0197 item.setId(mItemIdByChangeId.value(changeId)); 0198 auto fetchJob = new ItemFetchJob(item, this); 0199 fetchJob->fetchScope().fetchFullPayload(); 0200 AKVERIFYEXEC(fetchJob); 0201 QVERIFY(!fetchJob->items().isEmpty()); 0202 Item retrievedItem = fetchJob->items().first(); 0203 QVERIFY(retrievedItem.isValid()); 0204 QVERIFY(retrievedItem.hasPayload()); 0205 QVERIFY(retrievedItem.hasPayload<KCalendarCore::Event::Ptr>()); 0206 QVERIFY(retrievedItem.hasPayload<KCalendarCore::Incidence::Ptr>()); 0207 auto incidence = retrievedItem.payload<KCalendarCore::Incidence::Ptr>(); 0208 QCOMPARE(incidence->summary(), summary); 0209 QCOMPARE(incidence->uid(), uid); 0210 } 0211 } 0212 mItemIdByChangeId.clear(); 0213 } 0214 0215 void testDeleting_data() 0216 { 0217 QTest::addColumn<Akonadi::Item::List>("items"); 0218 QTest::addColumn<bool>("respectsCollectionRights"); 0219 QTest::addColumn<bool>("failureExpected"); 0220 QTest::addColumn<Akonadi::IncidenceChanger::ResultCode>("expectedResultCode"); 0221 0222 QTest::newRow("Delete empty list") << Item::List() << true << true; 0223 QTest::newRow("Delete invalid item") << (Item::List() << Item()) << true << true; 0224 0225 auto fetchJob = new ItemFetchJob(mCollection); 0226 fetchJob->fetchScope().fetchFullPayload(); 0227 AKVERIFYEXEC(fetchJob); 0228 Item::List items = fetchJob->items(); 0229 0230 // 5 Incidences were created in testCreating(). Keep this in sync. 0231 QCOMPARE(items.count(), 5); 0232 QTest::newRow("Simple delete") << (Item::List() << items.at(0)) << true << false << IncidenceChanger::ResultCodeSuccess; 0233 0234 QTest::newRow("Delete already deleted") << (Item::List() << items.at(0)) << true << false << IncidenceChanger::ResultCodeAlreadyDeleted; 0235 0236 QTest::newRow("Delete all others") << (Item::List() << items.at(1) << items.at(2)) << true << false << IncidenceChanger::ResultCodeSuccess; 0237 0238 Collection collectionWithoutRights = Collection(mCollection.id()); 0239 collectionWithoutRights.setRights(Collection::Rights()); 0240 Item item = items.at(3); 0241 item.setParentCollection(collectionWithoutRights); 0242 QTest::newRow("Delete can't delete") << (Item::List() << item) << true << false << IncidenceChanger::ResultCodePermissions; 0243 } 0244 0245 void testDeleting() 0246 { 0247 QFETCH(Akonadi::Item::List, items); 0248 QFETCH(bool, respectsCollectionRights); 0249 QFETCH(bool, failureExpected); 0250 mChanger->setRespectsCollectionRights(respectsCollectionRights); 0251 const int changeId = mChanger->deleteIncidences(items); 0252 0253 QVERIFY(failureExpected ^ (changeId != -1)); 0254 0255 if (!failureExpected) { 0256 QFETCH(Akonadi::IncidenceChanger::ResultCode, expectedResultCode); 0257 mIncidencesToDelete = 1; 0258 mExpectedResultByChangeId.insert(changeId, expectedResultCode); 0259 waitForSignals(); 0260 0261 if (expectedResultCode == IncidenceChanger::ResultCodeSuccess) { 0262 // Check that the incidence was really deleted 0263 for (const Akonadi::Item &item : std::as_const(items)) { 0264 auto fetchJob = new ItemFetchJob(item, this); 0265 fetchJob->fetchScope().fetchFullPayload(); 0266 QVERIFY(!fetchJob->exec()); 0267 QVERIFY(fetchJob->items().isEmpty()); 0268 delete fetchJob; 0269 } 0270 } 0271 } 0272 } 0273 0274 void testModifying_data() 0275 { 0276 QTest::addColumn<Akonadi::Item>("item"); 0277 QTest::addColumn<QString>("newSummary"); 0278 QTest::addColumn<bool>("respectsCollectionRights"); 0279 QTest::addColumn<int>("expectedRevision"); 0280 QTest::addColumn<bool>("failureExpected"); 0281 QTest::addColumn<Akonadi::IncidenceChanger::ResultCode>("expectedResultCode"); 0282 0283 QTest::newRow("Invalid item") << Item() << QString() << true << 0 << true; 0284 QTest::newRow("Valid item, invalid payload") << Item(1) << QString() << true << 0 << true; 0285 0286 Item item; 0287 item.setMimeType(Event::eventMimeType()); 0288 Incidence::Ptr incidence = Incidence::Ptr(new Event()); 0289 incidence->setUid(QStringLiteral("test123uid")); 0290 incidence->setSummary(QStringLiteral("summary")); 0291 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0292 auto job = new ItemCreateJob(item, mCollection, this); 0293 AKVERIFYEXEC(job); 0294 item = job->item(); 0295 incidence->setSummary(QStringLiteral("New Summary")); 0296 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0297 0298 QTest::newRow("Change summary") << item << "New Summary" << true << 1 << false << IncidenceChanger::ResultCodeSuccess; 0299 0300 Collection collectionWithoutRights = Collection(mCollection.id()); 0301 collectionWithoutRights.setRights(Collection::Rights()); 0302 item.setParentCollection(collectionWithoutRights); 0303 0304 QTest::newRow("Can't change") << item << "New Summary" << true << 1 << false << IncidenceChanger::ResultCodePermissions; 0305 } 0306 0307 void testModifying() 0308 { 0309 QFETCH(Akonadi::Item, item); 0310 QFETCH(QString, newSummary); 0311 QFETCH(bool, respectsCollectionRights); 0312 QFETCH(int, expectedRevision); 0313 QFETCH(bool, failureExpected); 0314 0315 mChanger->setRespectsCollectionRights(respectsCollectionRights); 0316 const int changeId = mChanger->modifyIncidence(item); 0317 QVERIFY(failureExpected ^ (changeId != -1)); 0318 0319 if (!failureExpected) { 0320 QFETCH(Akonadi::IncidenceChanger::ResultCode, expectedResultCode); 0321 0322 mIncidencesToModify = 1; 0323 mExpectedResultByChangeId.insert(changeId, expectedResultCode); 0324 waitForSignals(); 0325 auto fetchJob = new ItemFetchJob(item, this); 0326 fetchJob->fetchScope().fetchFullPayload(); 0327 AKVERIFYEXEC(fetchJob); 0328 QVERIFY(fetchJob->items().count() == 1); 0329 Item fetchedItem = fetchJob->items().constFirst(); 0330 QVERIFY(fetchedItem.isValid()); 0331 QVERIFY(fetchedItem.hasPayload<KCalendarCore::Incidence::Ptr>()); 0332 auto incidence = fetchedItem.payload<KCalendarCore::Incidence::Ptr>(); 0333 QCOMPARE(incidence->summary(), newSummary); 0334 QCOMPARE(incidence->revision(), expectedRevision); 0335 delete fetchJob; 0336 } 0337 } 0338 0339 void testModifyingAlarmSettings() 0340 { 0341 // A user should be able to change alarm settings independently 0342 // do not trigger a revision increment 0343 // kolab #1386 0344 Item item; 0345 item.setMimeType(Event::eventMimeType()); 0346 Incidence::Ptr incidence = Incidence::Ptr(new Event()); 0347 incidence->setUid(QStringLiteral("test123uid")); 0348 incidence->setSummary(QStringLiteral("summary")); 0349 incidence->setOrganizer(Person(QStringLiteral("orga"), QStringLiteral("orga@dev.nul"))); 0350 incidence->setDirtyFields(QSet<IncidenceBase::Field>()); 0351 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0352 auto job = new ItemCreateJob(item, mCollection, this); 0353 AKVERIFYEXEC(job); 0354 item = job->item(); 0355 Alarm::Ptr alarm = Alarm::Ptr(new Alarm(incidence.data())); 0356 alarm->setStartOffset(Duration(-15)); 0357 alarm->setType(Alarm::Display); 0358 incidence->addAlarm(alarm); 0359 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0360 0361 mChanger->setRespectsCollectionRights(true); 0362 const int changeId = mChanger->modifyIncidence(item); 0363 QVERIFY(changeId != -1); 0364 0365 mIncidencesToModify = 1; 0366 mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess); 0367 waitForSignals(); 0368 auto fetchJob = new ItemFetchJob(item, this); 0369 fetchJob->fetchScope().fetchFullPayload(); 0370 AKVERIFYEXEC(fetchJob); 0371 QVERIFY(fetchJob->items().count() == 1); 0372 Item fetchedItem = fetchJob->items().constFirst(); 0373 QVERIFY(fetchedItem.isValid()); 0374 QVERIFY(fetchedItem.hasPayload<KCalendarCore::Incidence::Ptr>()); 0375 auto incidence2 = fetchedItem.payload<KCalendarCore::Incidence::Ptr>(); 0376 QCOMPARE(incidence2->alarms().count(), 1); 0377 QCOMPARE(incidence2->revision(), 0); 0378 delete fetchJob; 0379 } 0380 0381 void testModifyRescedule_data() 0382 { 0383 // When a event is resceduled than all attendees part status should set to NEEDS-ACTION 0384 // kolab #4533 0385 QTest::addColumn<Akonadi::Item>("item"); 0386 QTest::addColumn<Event::Ptr>("event"); 0387 QTest::addColumn<bool>("expectReset"); 0388 0389 Attendee us(QString(), s_ourEmail); 0390 us.setStatus(Attendee::Accepted); 0391 Attendee mia(QStringLiteral("Mia Wallace"), QStringLiteral("mia@dev.nul")); 0392 mia.setStatus(Attendee::Declined); 0393 mia.setRSVP(false); 0394 Attendee vincent(QStringLiteral("Vincent"), QStringLiteral("vincent@dev.nul")); 0395 vincent.setStatus(Attendee::Delegated); 0396 Attendee jules(QStringLiteral("Jules"), QStringLiteral("jules@dev.nul")); 0397 jules.setStatus(Attendee::Accepted); 0398 jules.setRole(Attendee::NonParticipant); 0399 0400 // we as organizator 0401 Item item; 0402 item.setMimeType(Event::eventMimeType()); 0403 Event::Ptr incidence = Event::Ptr(new Event()); 0404 incidence->setUid(QStringLiteral("test123uid")); 0405 incidence->setDtStart(QDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), QTimeZone::utc())); 0406 incidence->setDtEnd(QDateTime(QDate(2006, 1, 8), QTime(14, 0, 0), QTimeZone::utc())); 0407 incidence->setAllDay(false); 0408 incidence->setLocation(QStringLiteral("location")); 0409 incidence->setOrganizer(Person(QString(), s_ourEmail)); 0410 incidence->addAttendee(us); 0411 incidence->addAttendee(mia); 0412 incidence->addAttendee(vincent); 0413 incidence->addAttendee(jules); 0414 incidence->setDirtyFields(QSet<IncidenceBase::Field>()); 0415 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0416 0417 { 0418 Event::Ptr event = Event::Ptr(new Event(*incidence)); 0419 event->setDtStart(QDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), QTimeZone::utc())); 0420 QCOMPARE(event->dirtyFields().count(), 1); 0421 QTest::newRow("organizator:start Date") << item << event << true; 0422 } 0423 0424 { 0425 Event::Ptr event = Event::Ptr(new Event(*incidence)); 0426 event->setDtEnd(QDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), QTimeZone::utc())); 0427 QCOMPARE(event->dirtyFields().count(), 1); 0428 QTest::newRow("organizator:end Date") << item << event << true; 0429 } 0430 0431 { 0432 Event::Ptr event = Event::Ptr(new Event(*incidence)); 0433 event->setAllDay(true); 0434 QCOMPARE(event->dirtyFields().count(), 2); 0435 QTest::newRow("organizator:allDay") << item << event << true; 0436 } 0437 0438 { 0439 Event::Ptr event = Event::Ptr(new Event(*incidence)); 0440 event->setLocation(QStringLiteral("location2")); 0441 QCOMPARE(event->dirtyFields().count(), 1); 0442 QTest::newRow("organizator:location") << item << event << true; 0443 } 0444 0445 { 0446 Event::Ptr event = Event::Ptr(new Event(*incidence)); 0447 event->setSummary(QStringLiteral("summary")); 0448 QCOMPARE(event->dirtyFields().count(), 1); 0449 QTest::newRow("organizator:summary") << item << event << false; 0450 } 0451 0452 // we are normal attendee 0453 Item item2; 0454 item2.setMimeType(Event::eventMimeType()); 0455 Event::Ptr incidence2 = Event::Ptr(new Event()); 0456 incidence2->setUid(QStringLiteral("test123uid")); 0457 incidence2->setDtStart(QDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), QTimeZone::utc())); 0458 incidence2->setDtEnd(QDateTime(QDate(2006, 1, 8), QTime(14, 0, 0), QTimeZone::utc())); 0459 incidence2->setAllDay(false); 0460 incidence2->setLocation(QStringLiteral("location")); 0461 incidence2->setOrganizer(Person(QStringLiteral("External organizator"), QStringLiteral("exorga@dev.nul"))); 0462 incidence2->addAttendee(us); 0463 incidence2->addAttendee(mia); 0464 incidence2->addAttendee(vincent); 0465 incidence2->addAttendee(jules); 0466 incidence2->setDirtyFields(QSet<IncidenceBase::Field>()); 0467 item2.setPayload<KCalendarCore::Incidence::Ptr>(incidence2); 0468 0469 { 0470 Event::Ptr event = Event::Ptr(new Event(*incidence2)); 0471 event->setDtStart(QDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), QTimeZone::utc())); 0472 QTest::newRow("attendee:start Date") << item2 << event << false; 0473 } 0474 0475 { 0476 Event::Ptr event = Event::Ptr(new Event(*incidence2)); 0477 event->setDtEnd(QDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), QTimeZone::utc())); 0478 QTest::newRow("attendee:end Date") << item2 << event << false; 0479 } 0480 0481 { 0482 Event::Ptr event = Event::Ptr(new Event(*incidence2)); 0483 event->setAllDay(false); 0484 QTest::newRow("attendee:allDay") << item2 << event << false; 0485 } 0486 0487 { 0488 Event::Ptr event = Event::Ptr(new Event(*incidence2)); 0489 event->setLocation(QStringLiteral("location2")); 0490 QTest::newRow("attendee:location") << item2 << event << false; 0491 } 0492 0493 { 0494 Event::Ptr event = Event::Ptr(new Event(*incidence2)); 0495 event->setSummary(QStringLiteral("summary")); 0496 QTest::newRow("attendee:summary") << item2 << event << false; 0497 } 0498 } 0499 0500 void testModifyRescedule() 0501 { 0502 QFETCH(Akonadi::Item, item); 0503 QFETCH(Event::Ptr, event); 0504 QFETCH(bool, expectReset); 0505 0506 item.setId(-1); 0507 auto job = new ItemCreateJob(item, mCollection, this); 0508 AKVERIFYEXEC(job); 0509 item = job->item(); 0510 item.setPayload<KCalendarCore::Incidence::Ptr>(event); 0511 0512 int revision = event->revision(); 0513 0514 mChanger->setRespectsCollectionRights(true); 0515 const int changeId = mChanger->modifyIncidence(item); 0516 QVERIFY(changeId != -1); 0517 0518 mIncidencesToModify = 1; 0519 mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess); 0520 waitForSignals(); 0521 auto fetchJob = new ItemFetchJob(item, this); 0522 fetchJob->fetchScope().fetchFullPayload(); 0523 AKVERIFYEXEC(fetchJob); 0524 QVERIFY(fetchJob->items().count() == 1); 0525 Item fetchedItem = fetchJob->items().constFirst(); 0526 0527 QVERIFY(fetchedItem.isValid()); 0528 QVERIFY(fetchedItem.hasPayload<KCalendarCore::Event::Ptr>()); 0529 auto incidence = fetchedItem.payload<KCalendarCore::Event::Ptr>(); 0530 0531 QCOMPARE(incidence->revision(), revision + 1); 0532 0533 if (expectReset) { 0534 if (incidence->organizer().email() == s_ourEmail) { 0535 QCOMPARE(incidence->attendeeByMail(s_ourEmail).status(), Attendee::Accepted); 0536 } else { 0537 QCOMPARE(incidence->attendeeByMail(s_ourEmail).status(), Attendee::NeedsAction); 0538 } 0539 QCOMPARE(incidence->attendeeByMail(QStringLiteral("mia@dev.nul")).status(), Attendee::NeedsAction); 0540 QCOMPARE(incidence->attendeeByMail(QStringLiteral("mia@dev.nul")).RSVP(), true); 0541 QCOMPARE(incidence->attendeeByMail(QStringLiteral("vincent@dev.nul")).status(), Attendee::Delegated); 0542 QCOMPARE(incidence->attendeeByMail(QStringLiteral("vincent@dev.nul")).RSVP(), false); 0543 QCOMPARE(incidence->attendeeByMail(QStringLiteral("jules@dev.nul")).status(), Attendee::Accepted); 0544 QCOMPARE(incidence->attendeeByMail(QStringLiteral("jules@dev.nul")).RSVP(), false); 0545 } else { 0546 QCOMPARE(incidence->attendeeByMail(s_ourEmail).status(), Attendee::Accepted); 0547 QCOMPARE(incidence->attendeeByMail(QStringLiteral("mia@dev.nul")).status(), Attendee::Declined); 0548 QCOMPARE(incidence->attendeeByMail(QStringLiteral("vincent@dev.nul")).status(), Attendee::Delegated); 0549 QCOMPARE(incidence->attendeeByMail(QStringLiteral("jules@dev.nul")).status(), Attendee::Accepted); 0550 } 0551 delete fetchJob; 0552 } 0553 0554 void testMassModifyForConflicts_data() 0555 { 0556 QTest::addColumn<Akonadi::Item>("item"); 0557 QTest::addColumn<bool>("waitForPreviousJob"); 0558 QTest::addColumn<int>("numberOfModifications"); 0559 0560 // Create an incidence 0561 Item item; 0562 item.setMimeType(Event::eventMimeType()); 0563 Incidence::Ptr incidence = Incidence::Ptr(new Event()); 0564 incidence->setUid(QStringLiteral("test123uid")); 0565 incidence->setSummary(QStringLiteral("summary")); 0566 item.setPayload<KCalendarCore::Incidence::Ptr>(incidence); 0567 auto job = new ItemCreateJob(item, mCollection, this); 0568 AKVERIFYEXEC(job); 0569 item = job->item(); 0570 0571 QTest::newRow("15 modifications in sequence") << item << true << 15; 0572 QTest::newRow("15 modifications in parallel") << item << false << 15; 0573 } 0574 0575 void testMassModifyForConflicts() 0576 { 0577 QFETCH(Akonadi::Item, item); 0578 QFETCH(bool, waitForPreviousJob); 0579 QFETCH(int, numberOfModifications); 0580 mDiscardedEqualsSuccess = true; 0581 0582 Q_ASSERT(numberOfModifications > 0); 0583 0584 if (!waitForPreviousJob) { 0585 mIncidencesToModify = numberOfModifications; 0586 } 0587 0588 int changeId = -1; 0589 for (int i = 0; i < numberOfModifications; ++i) { 0590 auto incidence = item.payload<KCalendarCore::Incidence::Ptr>(); 0591 Q_ASSERT(incidence); 0592 incidence->setSummary(QString::number(i)); 0593 changeId = mChanger->modifyIncidence(item); 0594 QVERIFY(changeId != -1); 0595 0596 if (waitForPreviousJob) { 0597 mIncidencesToModify = 1; 0598 mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess); 0599 waitForSignals(); 0600 auto fetchJob = new ItemFetchJob(item, this); 0601 fetchJob->fetchScope().fetchFullPayload(); 0602 AKVERIFYEXEC(fetchJob); 0603 QVERIFY(fetchJob->items().count() == 1); 0604 QCOMPARE(fetchJob->items().first().payload<KCalendarCore::Incidence::Ptr>()->summary(), QString::number(i)); 0605 } 0606 } 0607 0608 if (!waitForPreviousJob) { 0609 mIncidencesToModify = numberOfModifications; 0610 // Wait for the last one 0611 mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess); 0612 waitForChange(changeId); 0613 auto fetchJob = new ItemFetchJob(item, this); 0614 fetchJob->fetchScope().fetchFullPayload(); 0615 AKVERIFYEXEC(fetchJob); 0616 QVERIFY(fetchJob->items().count() == 1); 0617 QCOMPARE(fetchJob->items().first().payload<KCalendarCore::Incidence::Ptr>()->summary(), QString::number(numberOfModifications - 1)); 0618 if (mIncidencesToModify > 0) { 0619 waitForSignals(); 0620 } 0621 } 0622 0623 mDiscardedEqualsSuccess = false; 0624 } 0625 0626 void testAtomicOperations_data() 0627 { 0628 QTest::addColumn<Akonadi::Item::List>("items"); 0629 QTest::addColumn<QList<Akonadi::IncidenceChanger::ChangeType>>("changeTypes"); 0630 QTest::addColumn<QList<bool>>("failureExpectedList"); 0631 QTest::addColumn<QList<Akonadi::IncidenceChanger::ResultCode>>("expectedResults"); 0632 QTest::addColumn<QList<Akonadi::Collection::Rights>>("rights"); 0633 QTest::addColumn<bool>("permissionsOrRollback"); 0634 0635 Akonadi::Item::List items; 0636 QList<Akonadi::IncidenceChanger::ChangeType> changeTypes; 0637 QList<bool> failureExpectedList; 0638 QList<Akonadi::IncidenceChanger::ResultCode> expectedResults; 0639 QList<Akonadi::Collection::Rights> rights; 0640 const Collection::Rights allRights = Collection::AllRights; 0641 const Collection::Rights noRights = Collection::Rights(); 0642 //------------------------------------------------------------------------------------------ 0643 // Create two incidences, should succeed 0644 items << item() << item(); 0645 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate; 0646 failureExpectedList << false << false; 0647 expectedResults << IncidenceChanger::ResultCodeSuccess << IncidenceChanger::ResultCodeSuccess; 0648 rights << allRights << allRights; 0649 0650 QTest::newRow("create two - success ") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0651 //------------------------------------------------------------------------------------------ 0652 changeTypes.clear(); 0653 changeTypes << IncidenceChanger::ChangeTypeModify << IncidenceChanger::ChangeTypeModify; 0654 items.clear(); 0655 items << createItem(mCollection) << createItem(mCollection); 0656 0657 QTest::newRow("modify two - success ") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0658 //------------------------------------------------------------------------------------------ 0659 changeTypes.clear(); 0660 changeTypes << IncidenceChanger::ChangeTypeDelete << IncidenceChanger::ChangeTypeDelete; 0661 QTest::newRow("delete two - success ") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0662 //------------------------------------------------------------------------------------------ 0663 // Creation succeeds but deletion doesn't ( invalid item case ) 0664 items.clear(); 0665 items << item() << Item(); // Invalid item on purpose 0666 changeTypes.clear(); 0667 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeDelete; 0668 failureExpectedList.clear(); 0669 failureExpectedList << false << true; 0670 expectedResults.clear(); 0671 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback; 0672 rights.clear(); 0673 rights << allRights << allRights; 0674 0675 QTest::newRow("create,try delete") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0676 //------------------------------------------------------------------------------------------ 0677 // deletion doesn't succeed, but creation does ( invalid item case ) 0678 items.clear(); 0679 items << Item() << item(); // Invalid item on purpose 0680 changeTypes.clear(); 0681 changeTypes << IncidenceChanger::ChangeTypeDelete << IncidenceChanger::ChangeTypeCreate; 0682 failureExpectedList.clear(); 0683 failureExpectedList << true << false; 0684 expectedResults.clear(); 0685 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback; 0686 rights.clear(); 0687 rights << allRights << allRights; 0688 0689 QTest::newRow("try delete,create") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0690 //------------------------------------------------------------------------------------------ 0691 // Creation succeeds but deletion doesn't ( valid, inexistent item case ) 0692 items.clear(); 0693 items << item() << Item(10101010); 0694 changeTypes.clear(); 0695 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeDelete; 0696 failureExpectedList.clear(); 0697 failureExpectedList << false << false; 0698 expectedResults.clear(); 0699 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeJobError; 0700 rights.clear(); 0701 rights << allRights << allRights; 0702 0703 QTest::newRow("create,try delete v2") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0704 //------------------------------------------------------------------------------------------ 0705 // deletion doesn't succeed, but creation does ( valid, inexistent item case ) 0706 items.clear(); 0707 items << Item(10101010) << item(); 0708 changeTypes.clear(); 0709 changeTypes << IncidenceChanger::ChangeTypeDelete << IncidenceChanger::ChangeTypeCreate; 0710 failureExpectedList.clear(); 0711 failureExpectedList << false << false; 0712 expectedResults.clear(); 0713 expectedResults << IncidenceChanger::ResultCodeJobError << IncidenceChanger::ResultCodeRolledback; 0714 rights.clear(); 0715 rights << allRights << allRights; 0716 0717 QTest::newRow("try delete,create v2") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0718 //------------------------------------------------------------------------------------------ 0719 // deletion doesn't succeed, but creation does ( NO ACL case ) 0720 items.clear(); 0721 items << createItem(mCollection) << item(); 0722 changeTypes.clear(); 0723 changeTypes << IncidenceChanger::ChangeTypeDelete << IncidenceChanger::ChangeTypeCreate; 0724 failureExpectedList.clear(); 0725 failureExpectedList << false << false; 0726 expectedResults.clear(); 0727 expectedResults << IncidenceChanger::ResultCodePermissions << IncidenceChanger::ResultCodeRolledback; 0728 rights.clear(); 0729 rights << noRights << allRights; 0730 0731 QTest::newRow("try delete(ACL),create") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0732 //------------------------------------------------------------------------------------------ 0733 // Creation succeeds but deletion doesn't ( NO ACL case ) 0734 items.clear(); 0735 items << item() << createItem(mCollection); 0736 changeTypes.clear(); 0737 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeDelete; 0738 failureExpectedList.clear(); 0739 failureExpectedList << false << false; 0740 expectedResults.clear(); 0741 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodePermissions; 0742 rights.clear(); 0743 rights << allRights << noRights; 0744 0745 QTest::newRow("create,try delete(ACL)") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0746 //------------------------------------------------------------------------------------------ 0747 // 1 successful modification, 1 failed creation 0748 changeTypes.clear(); 0749 changeTypes << IncidenceChanger::ChangeTypeModify << IncidenceChanger::ChangeTypeCreate; 0750 items.clear(); 0751 items << createItem(mCollection) << Item(); 0752 failureExpectedList.clear(); 0753 failureExpectedList << false << true; 0754 expectedResults.clear(); 0755 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback; 0756 rights.clear(); 0757 rights << allRights << allRights; 0758 0759 QTest::newRow("modify,try create") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0760 //------------------------------------------------------------------------------------------ 0761 // 1 successful modification, 1 failed creation 0762 changeTypes.clear(); 0763 changeTypes << IncidenceChanger::ChangeTypeModify << IncidenceChanger::ChangeTypeCreate; 0764 items.clear(); 0765 items << createItem(mCollection) << item(); 0766 failureExpectedList.clear(); 0767 failureExpectedList << false << false; 0768 expectedResults.clear(); 0769 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodePermissions; 0770 rights.clear(); 0771 rights << allRights << noRights; 0772 0773 QTest::newRow("modify,try create v2") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0774 //------------------------------------------------------------------------------------------ 0775 // 1 failed creation, 1 successful modification 0776 changeTypes.clear(); 0777 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeModify; 0778 items.clear(); 0779 items << Item() << createItem(mCollection); 0780 failureExpectedList.clear(); 0781 failureExpectedList << true << false; 0782 expectedResults.clear(); 0783 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback; 0784 rights.clear(); 0785 rights << allRights << allRights; 0786 0787 QTest::newRow("try create,modify") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0788 //------------------------------------------------------------------------------------------ 0789 // 1 failed creation, 1 successful modification 0790 changeTypes.clear(); 0791 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeModify; 0792 items.clear(); 0793 items << item() << createItem(mCollection); 0794 failureExpectedList.clear(); 0795 failureExpectedList << false << false; 0796 expectedResults.clear(); 0797 expectedResults << IncidenceChanger::ResultCodePermissions << IncidenceChanger::ResultCodeRolledback; 0798 rights.clear(); 0799 rights << noRights << allRights; 0800 0801 QTest::newRow("try create,modify v2") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0802 //------------------------------------------------------------------------------------------ 0803 // 4 creations, last one fails 0804 changeTypes.clear(); 0805 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate 0806 << IncidenceChanger::ChangeTypeCreate; 0807 items.clear(); 0808 items << item() << item() << item() << item(); 0809 failureExpectedList.clear(); 0810 failureExpectedList << false << false << false << false; 0811 expectedResults.clear(); 0812 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback 0813 << IncidenceChanger::ResultCodePermissions; 0814 rights.clear(); 0815 rights << allRights << allRights << allRights << noRights; 0816 0817 QTest::newRow("create 4, last fails") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0818 //------------------------------------------------------------------------------------------ 0819 // 4 creations, first one fails 0820 changeTypes.clear(); 0821 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate 0822 << IncidenceChanger::ChangeTypeCreate; 0823 items.clear(); 0824 items << item() << item() << item() << item(); 0825 failureExpectedList.clear(); 0826 failureExpectedList << false << false << false << false; 0827 expectedResults.clear(); 0828 expectedResults << IncidenceChanger::ResultCodePermissions << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodeRolledback 0829 << IncidenceChanger::ResultCodeRolledback; 0830 rights.clear(); 0831 rights << noRights << allRights << allRights << allRights; 0832 0833 QTest::newRow("create 4, first fails") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0834 //------------------------------------------------------------------------------------------ 0835 // 4 creations, second one fails 0836 changeTypes.clear(); 0837 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate 0838 << IncidenceChanger::ChangeTypeCreate; 0839 items.clear(); 0840 items << item() << item() << item() << item(); 0841 failureExpectedList.clear(); 0842 failureExpectedList << false << false << false << false; 0843 expectedResults.clear(); 0844 expectedResults << IncidenceChanger::ResultCodeRolledback << IncidenceChanger::ResultCodePermissions << IncidenceChanger::ResultCodeRolledback 0845 << IncidenceChanger::ResultCodeRolledback; 0846 rights.clear(); 0847 rights << allRights << noRights << allRights << allRights; 0848 0849 QTest::newRow("create 4, second fails") << items << changeTypes << failureExpectedList << expectedResults << rights << false; 0850 //------------------------------------------------------------------------------------------ 0851 // 4 fails 0852 changeTypes.clear(); 0853 changeTypes << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate << IncidenceChanger::ChangeTypeCreate 0854 << IncidenceChanger::ChangeTypeCreate; 0855 items.clear(); 0856 items << item() << item() << item() << item(); 0857 failureExpectedList.clear(); 0858 failureExpectedList << false << false << false << false; 0859 expectedResults.clear(); 0860 expectedResults << IncidenceChanger::ResultCodePermissions << IncidenceChanger::ResultCodePermissions << IncidenceChanger::ResultCodePermissions 0861 << IncidenceChanger::ResultCodePermissions; 0862 rights.clear(); 0863 rights << noRights << noRights << noRights << noRights; 0864 0865 QTest::newRow("create 4, all fail") << items << changeTypes << failureExpectedList << expectedResults << rights << true; 0866 //------------------------------------------------------------------------------------------ 0867 //------------------------------------------------------------------------------------------ 0868 //------------------------------------------------------------------------------------------ 0869 //------------------------------------------------------------------------------------------ 0870 } 0871 0872 void testAtomicOperations() 0873 { 0874 QFETCH(Akonadi::Item::List, items); 0875 QFETCH(QList<Akonadi::IncidenceChanger::ChangeType>, changeTypes); 0876 QFETCH(QList<bool>, failureExpectedList); 0877 QFETCH(QList<Akonadi::IncidenceChanger::ResultCode>, expectedResults); 0878 QFETCH(QList<Akonadi::Collection::Rights>, rights); 0879 QFETCH(bool, permissionsOrRollback); 0880 0881 QCOMPARE(items.count(), changeTypes.count()); 0882 QCOMPARE(items.count(), failureExpectedList.count()); 0883 QCOMPARE(items.count(), expectedResults.count()); 0884 QCOMPARE(items.count(), rights.count()); 0885 0886 mPermissionsOrRollback = permissionsOrRollback; 0887 mChanger->setDefaultCollection(mCollection); 0888 mChanger->setRespectsCollectionRights(true); 0889 mChanger->setDestinationPolicy(IncidenceChanger::DestinationPolicyNeverAsk); 0890 mChanger->startAtomicOperation(); 0891 mIncidencesToAdd = 0; 0892 mIncidencesToModify = 0; 0893 mIncidencesToDelete = 0; 0894 for (int i = 0; i < items.count(); ++i) { 0895 mCollection.setRights(rights[i]); 0896 mChanger->setDefaultCollection(mCollection); 0897 const Akonadi::Item item = items[i]; 0898 int changeId = -1; 0899 switch (changeTypes[i]) { 0900 case IncidenceChanger::ChangeTypeCreate: 0901 changeId = mChanger->createIncidence(item.hasPayload() ? item.payload<KCalendarCore::Incidence::Ptr>() : Incidence::Ptr()); 0902 if (changeId != -1) { 0903 ++mIncidencesToAdd; 0904 } 0905 break; 0906 case IncidenceChanger::ChangeTypeDelete: 0907 changeId = mChanger->deleteIncidence(item); 0908 if (changeId != -1) { 0909 ++mIncidencesToDelete; 0910 } 0911 break; 0912 case IncidenceChanger::ChangeTypeModify: 0913 QVERIFY(item.isValid()); 0914 QVERIFY(item.hasPayload<KCalendarCore::Incidence::Ptr>()); 0915 item.payload<KCalendarCore::Incidence::Ptr>()->setSummary(QStringLiteral("Changed")); 0916 changeId = mChanger->modifyIncidence(item); 0917 if (changeId != -1) { 0918 ++mIncidencesToModify; 0919 } 0920 break; 0921 default: 0922 QVERIFY(false); 0923 } 0924 QVERIFY(!((changeId == -1) ^ failureExpectedList[i])); 0925 if (changeId != -1) { 0926 mExpectedResultByChangeId.insert(changeId, expectedResults[i]); 0927 } 0928 } 0929 mChanger->endAtomicOperation(); 0930 0931 waitForSignals(); 0932 0933 // Validate: 0934 for (int i = 0; i < items.count(); ++i) { 0935 const bool expectedSuccess = (expectedResults[i] == IncidenceChanger::ResultCodeSuccess); 0936 mCollection.setRights(rights[i]); 0937 0938 Akonadi::Item item = items[i]; 0939 0940 switch (changeTypes[i]) { 0941 case IncidenceChanger::ChangeTypeCreate: 0942 if (expectedSuccess) { 0943 QVERIFY(item.hasPayload<KCalendarCore::Incidence::Ptr>()); 0944 auto incidence = item.payload<KCalendarCore::Incidence::Ptr>(); 0945 QVERIFY(incidence); 0946 QVERIFY(!incidence->uid().isEmpty()); 0947 QVERIFY(mItemIdByUid.contains(incidence->uid())); 0948 auto fJob = new ItemFetchJob(Item(mItemIdByUid.value(incidence->uid()))); 0949 fJob->fetchScope().fetchFullPayload(); 0950 AKVERIFYEXEC(fJob); 0951 QCOMPARE(fJob->items().count(), 1); 0952 QVERIFY(fJob->items().constFirst().isValid()); 0953 QVERIFY(fJob->items().constFirst().hasPayload()); 0954 QVERIFY(fJob->items().constFirst().hasPayload<KCalendarCore::Incidence::Ptr>()); 0955 QCOMPARE(item.payload<KCalendarCore::Incidence::Ptr>()->uid(), fJob->items().constFirst().payload<KCalendarCore::Incidence::Ptr>()->uid()); 0956 } 0957 break; 0958 case IncidenceChanger::ChangeTypeDelete: 0959 if (expectedSuccess) { 0960 auto fJob = new ItemFetchJob(Item(item.id())); 0961 QVERIFY(!fJob->exec()); 0962 } 0963 break; 0964 case IncidenceChanger::ChangeTypeModify: 0965 if (expectedSuccess) { 0966 auto fJob = new ItemFetchJob(Item(item.id())); 0967 fJob->fetchScope().fetchFullPayload(); 0968 AKVERIFYEXEC(fJob); 0969 QCOMPARE(item.payload<KCalendarCore::Incidence::Ptr>()->summary(), 0970 fJob->items().first().payload<KCalendarCore::Incidence::Ptr>()->summary()); 0971 } 0972 break; 0973 default: 0974 QVERIFY(false); 0975 } 0976 } 0977 mPermissionsOrRollback = false; 0978 } 0979 0980 void testAdjustRecurrence_data() 0981 { 0982 QTest::addColumn<bool>("allDay"); 0983 QTest::addColumn<QDateTime>("dtStart"); 0984 QTest::addColumn<QDateTime>("dtEnd"); 0985 QTest::addColumn<int>("offsetToMove"); 0986 QTest::addColumn<int>("frequency"); 0987 QTest::addColumn<KCalendarCore::RecurrenceRule::PeriodType>("recurrenceType"); 0988 0989 // For weekly recurrences 0990 QTest::addColumn<QBitArray>("weekDays"); 0991 QTest::addColumn<QBitArray>("expectedWeekDays"); 0992 0993 // Recurrence end 0994 QTest::addColumn<QDate>("recurrenceEnd"); 0995 QTest::addColumn<QDate>("expectedRecurrenceEnd"); 0996 0997 const QDateTime dtStart = QDateTime(QDate::currentDate(), QTime(8, 0)); 0998 const QDateTime dtEnd = dtStart.addSecs(3600); 0999 const int one_day = 3600 * 24; 1000 const int one_hour = 3600; 1001 QBitArray days(7); 1002 QBitArray expectedDays(7); 1003 1004 //------------------------------------------------------------------------- 1005 days.setBit(dtStart.date().dayOfWeek() - 1); 1006 expectedDays.setBit(dtStart.addSecs(one_day).date().dayOfWeek() - 1); 1007 1008 QTest::newRow("weekly") << false << dtStart << dtEnd << one_day << 1 << KCalendarCore::RecurrenceRule::rWeekly << days << expectedDays << QDate() 1009 << QDate(); 1010 //------------------------------------------------------------------------- 1011 days.fill(false); 1012 days.setBit(dtStart.date().dayOfWeek() - 1); 1013 expectedDays.setBit(dtStart.addSecs(one_day).date().dayOfWeek() - 1); 1014 QTest::newRow("weekly allday") << true << QDateTime(dtStart.date().startOfDay()) << QDateTime(dtEnd.date().startOfDay()) << one_day << 1 1015 << KCalendarCore::RecurrenceRule::rWeekly << days << expectedDays << QDate() << QDate(); 1016 //------------------------------------------------------------------------- 1017 // Here nothing should change 1018 days.fill(false); 1019 days.setBit(dtStart.date().dayOfWeek() - 1); 1020 1021 QTest::newRow("weekly nop") << false << dtStart << dtEnd << one_hour << 1 << KCalendarCore::RecurrenceRule::rWeekly << days << days << QDate() 1022 << QDate(); 1023 //------------------------------------------------------------------------- 1024 // Test with multiple week days. Only the weekday from the old DTSTART should be unset. 1025 days.fill(true); 1026 expectedDays = days; 1027 expectedDays.clearBit(dtStart.date().dayOfWeek() - 1); 1028 QTest::newRow("weekly multiple") << false << dtStart << dtEnd << one_day << 1 << KCalendarCore::RecurrenceRule::rWeekly << days << expectedDays 1029 << QDate() << QDate(); 1030 //------------------------------------------------------------------------- 1031 // Testing moving an event such that DTSTART > recurrence end, which would 1032 // result in the event disappearing from all views. 1033 QTest::newRow("recur end") << false << dtStart << dtEnd << one_day * 7 << 1 << KCalendarCore::RecurrenceRule::rDaily << QBitArray() << QBitArray() 1034 << dtStart.date().addDays(3) << QDate(); 1035 //------------------------------------------------------------------------- 1036 mCollection.setRights(Collection::Rights(Collection::AllRights)); 1037 } 1038 1039 void testAdjustRecurrence() 1040 { 1041 QFETCH(bool, allDay); 1042 QFETCH(QDateTime, dtStart); 1043 QFETCH(QDateTime, dtEnd); 1044 QFETCH(int, offsetToMove); 1045 QFETCH(int, frequency); 1046 QFETCH(KCalendarCore::RecurrenceRule::PeriodType, recurrenceType); 1047 QFETCH(QBitArray, weekDays); 1048 QFETCH(QBitArray, expectedWeekDays); 1049 QFETCH(QDate, recurrenceEnd); 1050 QFETCH(QDate, expectedRecurrenceEnd); 1051 1052 Event::Ptr incidence = Event::Ptr(new Event()); 1053 incidence->setSummary(QStringLiteral("random summary")); 1054 incidence->setDtStart(dtStart); 1055 incidence->setDtEnd(dtEnd); 1056 incidence->setAllDay(allDay); 1057 1058 Recurrence *recurrence = incidence->recurrence(); 1059 1060 switch (recurrenceType) { 1061 case KCalendarCore::RecurrenceRule::rDaily: 1062 recurrence->setDaily(frequency); 1063 break; 1064 case KCalendarCore::RecurrenceRule::rWeekly: 1065 recurrence->setWeekly(frequency, weekDays); 1066 break; 1067 default: 1068 // Not tested yet 1069 Q_ASSERT(false); 1070 QVERIFY(false); 1071 } 1072 1073 if (recurrenceEnd.isValid()) { 1074 recurrence->setEndDate(recurrenceEnd); 1075 } 1076 1077 // Create the recurring incidence 1078 int changeId = mChanger->createIncidence(incidence, mCollection); 1079 QVERIFY(changeId != -1); 1080 mIncidencesToAdd = 1; 1081 mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess); 1082 waitForSignals(); 1083 1084 // Now lets move it 1085 Incidence::Ptr originalIncidence = Incidence::Ptr(incidence->clone()); 1086 incidence->setDtStart(dtStart.addSecs(offsetToMove)); 1087 1088 incidence->setDtEnd(dtEnd.addSecs(offsetToMove)); 1089 mLastItemCreated.setPayload(incidence); 1090 changeId = mChanger->modifyIncidence(mLastItemCreated, originalIncidence); 1091 QVERIFY(changeId != -1); 1092 mIncidencesToModify = 1; 1093 mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess); 1094 waitForSignals(); 1095 1096 // Now check the results 1097 switch (recurrenceType) { 1098 case KCalendarCore::RecurrenceRule::rDaily: 1099 break; 1100 case KCalendarCore::RecurrenceRule::rWeekly: 1101 QCOMPARE(incidence->recurrence()->days(), expectedWeekDays); 1102 if (weekDays != expectedWeekDays) { 1103 QVERIFY(incidence->dirtyFields().contains(IncidenceBase::FieldRecurrence)); 1104 } 1105 break; 1106 default: 1107 // Not tested yet 1108 Q_ASSERT(false); 1109 QVERIFY(false); 1110 } 1111 1112 if (recurrenceEnd.isValid() && !expectedRecurrenceEnd.isValid()) { 1113 QVERIFY(incidence->recurrence()->endDate() >= incidence->dtStart().date()); 1114 QVERIFY(incidence->dirtyFields().contains(IncidenceBase::FieldRecurrence)); 1115 } 1116 } 1117 1118 public Q_SLOTS: 1119 1120 void waitForSignals() 1121 { 1122 QTestEventLoop::instance().enterLoop(10); 1123 1124 if (QTestEventLoop::instance().timeout()) { 1125 qDebug() << "Remaining: " << mIncidencesToAdd << mIncidencesToDelete << mIncidencesToModify; 1126 } 1127 QVERIFY(!QTestEventLoop::instance().timeout()); 1128 } 1129 1130 // Waits for a specific change 1131 void waitForChange(int changeId) 1132 { 1133 mChangeToWaitFor = changeId; 1134 1135 int i = 0; 1136 while (mChangeToWaitFor != -1 && i++ < 10) { // wait 10 seconds max. 1137 QTest::qWait(100); 1138 } 1139 1140 QVERIFY(mChangeToWaitFor == -1); 1141 } 1142 1143 void deleteFinished(int changeId, const QList<Akonadi::Item::Id> &deletedIds, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorMessage) 1144 { 1145 QVERIFY(changeId != -1); 1146 mChangeToWaitFor = -1; 1147 --mIncidencesToDelete; 1148 1149 if (resultCode != IncidenceChanger::ResultCodeSuccess) { 1150 qDebug() << "Error string is " << errorMessage; 1151 } else { 1152 QVERIFY(!deletedIds.isEmpty()); 1153 for (Akonadi::Item::Id id : std::as_const(deletedIds)) { 1154 QVERIFY(id != -1); 1155 } 1156 } 1157 1158 compareExpectedResult(resultCode, mExpectedResultByChangeId[changeId], QStringLiteral("createFinished")); 1159 1160 maybeQuitEventLoop(); 1161 } 1162 1163 void createFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString) 1164 { 1165 QVERIFY(changeId != -1); 1166 mChangeToWaitFor = -1; 1167 --mIncidencesToAdd; 1168 1169 if (resultCode == IncidenceChanger::ResultCodeSuccess) { 1170 QVERIFY(item.isValid()); 1171 QVERIFY(item.parentCollection().isValid()); 1172 mItemIdByChangeId.insert(changeId, item.id()); 1173 QVERIFY(item.hasPayload()); 1174 auto incidence = item.payload<KCalendarCore::Incidence::Ptr>(); 1175 mItemIdByUid.insert(incidence->uid(), item.id()); 1176 mLastItemCreated = item; 1177 } else { 1178 qDebug() << "Error string is " << errorString; 1179 } 1180 1181 compareExpectedResult(resultCode, mExpectedResultByChangeId[changeId], QStringLiteral("createFinished")); 1182 1183 qDebug() << "Createfinished " << mIncidencesToAdd; 1184 maybeQuitEventLoop(); 1185 } 1186 1187 void modifyFinished(int changeId, const Akonadi::Item &item, Akonadi::IncidenceChanger::ResultCode resultCode, const QString &errorString) 1188 { 1189 mChangeToWaitFor = -1; 1190 --mIncidencesToModify; 1191 QVERIFY(changeId != -1); 1192 1193 if (resultCode == IncidenceChanger::ResultCodeSuccess) { 1194 QVERIFY(item.isValid()); 1195 } else { 1196 qDebug() << "Error string is " << errorString; 1197 } 1198 1199 compareExpectedResult(resultCode, mExpectedResultByChangeId[changeId], QStringLiteral("modifyFinished")); 1200 1201 maybeQuitEventLoop(); 1202 } 1203 1204 void maybeQuitEventLoop() 1205 { 1206 if (mIncidencesToDelete == 0 && mIncidencesToAdd == 0 && mIncidencesToModify == 0) { 1207 QTestEventLoop::instance().exitLoop(); 1208 } 1209 } 1210 1211 void testDefaultCollection() 1212 { 1213 const Collection newCollection(42); 1214 IncidenceChanger changer; 1215 QCOMPARE(changer.defaultCollection(), Collection()); 1216 changer.setDefaultCollection(newCollection); 1217 QCOMPARE(changer.defaultCollection(), newCollection); 1218 } 1219 1220 void testDestinationPolicy() 1221 { 1222 IncidenceChanger changer; 1223 QCOMPARE(changer.destinationPolicy(), IncidenceChanger::DestinationPolicyDefault); 1224 changer.setDestinationPolicy(IncidenceChanger::DestinationPolicyNeverAsk); 1225 QCOMPARE(changer.destinationPolicy(), IncidenceChanger::DestinationPolicyNeverAsk); 1226 } 1227 1228 void testDialogsOnError() 1229 { 1230 IncidenceChanger changer; 1231 QCOMPARE(changer.showDialogsOnError(), true); 1232 changer.setShowDialogsOnError(false); 1233 QCOMPARE(changer.showDialogsOnError(), false); 1234 } 1235 1236 void testRespectsCollectionRights() 1237 { 1238 IncidenceChanger changer; 1239 QCOMPARE(changer.respectsCollectionRights(), true); 1240 changer.setRespectsCollectionRights(false); 1241 QCOMPARE(changer.respectsCollectionRights(), false); 1242 } 1243 1244 void compareExpectedResult(IncidenceChanger::ResultCode result, IncidenceChanger::ResultCode expected, const QString &str) 1245 { 1246 if (mPermissionsOrRollback) { 1247 if (expected == IncidenceChanger::ResultCodePermissions) { 1248 expected = IncidenceChanger::ResultCodeRolledback; 1249 } 1250 1251 if (result == IncidenceChanger::ResultCodePermissions) { 1252 result = IncidenceChanger::ResultCodeRolledback; 1253 } 1254 } 1255 1256 if (mDiscardedEqualsSuccess) { 1257 if (expected == IncidenceChanger::ResultCodeModificationDiscarded) { 1258 expected = IncidenceChanger::ResultCodeSuccess; 1259 } 1260 1261 if (result == IncidenceChanger::ResultCodeModificationDiscarded) { 1262 result = IncidenceChanger::ResultCodeSuccess; 1263 } 1264 } 1265 1266 if (result != expected) { 1267 qDebug() << str << "Expected " << expected << " got " << result; 1268 } 1269 1270 QCOMPARE(result, expected); 1271 } 1272 }; 1273 1274 QTEST_AKONADIMAIN(IncidenceChangerTest) 1275 1276 #include "incidencechangertest.moc"