File indexing completed on 2024-11-10 04:40:16
0001 /* 0002 SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <QObject> 0008 0009 #include "attributefactory.h" 0010 #include "control.h" 0011 #include "item.h" 0012 #include "itemcreatejob.h" 0013 #include "itemfetchjob.h" 0014 #include "itemfetchscope.h" 0015 #include "itemmodifyjob.h" 0016 #include "monitor.h" 0017 #include "qtest_akonadi.h" 0018 #include "resourceselectjob_p.h" 0019 #include "tagattribute.h" 0020 #include "tagcreatejob.h" 0021 #include "tagdeletejob.h" 0022 #include "tagfetchjob.h" 0023 #include "tagfetchscope.h" 0024 #include "tagmodifyjob.h" 0025 0026 using namespace Akonadi; 0027 0028 class TagTest : public QObject 0029 { 0030 Q_OBJECT 0031 0032 private Q_SLOTS: 0033 void initTestCase(); 0034 0035 void testTag(); 0036 void testCreateFetch(); 0037 void testRID(); 0038 void testDelete(); 0039 void testDeleteRIDIsolation(); 0040 void testModify(); 0041 void testModifyFromResource(); 0042 void testCreateMerge(); 0043 void testAttributes(); 0044 void testTagItem(); 0045 void testCreateItem(); 0046 void testCreateItemWithTags(); 0047 void testRIDIsolation(); 0048 void testFetchTagIdWithItem(); 0049 void testFetchFullTagWithItem(); 0050 void testModifyItemWithTagByGID(); 0051 void testModifyItemWithTagByRID(); 0052 void testMonitor(); 0053 void testTagAttributeConfusionBug(); 0054 void testFetchItemsByTag(); 0055 void tagModifyJobShouldOnlySendModifiedAttributes(); 0056 }; 0057 0058 void TagTest::initTestCase() 0059 { 0060 AkonadiTest::checkTestIsIsolated(); 0061 AkonadiTest::setAllResourcesOffline(); 0062 AttributeFactory::registerAttribute<TagAttribute>(); 0063 qRegisterMetaType<Akonadi::Tag>(); 0064 qRegisterMetaType<QSet<Akonadi::Tag>>(); 0065 qRegisterMetaType<Akonadi::Item::List>(); 0066 0067 // Delete the default Knut tag - it's interfering with this test 0068 auto fetchJob = new TagFetchJob(this); 0069 AKVERIFYEXEC(fetchJob); 0070 QCOMPARE(fetchJob->tags().size(), 1); 0071 auto deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); 0072 AKVERIFYEXEC(deleteJob); 0073 } 0074 0075 void TagTest::testTag() 0076 { 0077 Tag tag1; 0078 Tag tag2; 0079 0080 // Invalid tags are equal 0081 QVERIFY(tag1 == tag2); 0082 0083 // Invalid tags with different GIDs are not equal 0084 tag1.setGid("GID1"); 0085 QVERIFY(tag1 != tag2); 0086 tag2.setGid("GID2"); 0087 QVERIFY(tag1 != tag2); 0088 0089 // Invalid tags with equal GIDs are equal 0090 tag1.setGid("GID2"); 0091 QVERIFY(tag1 == tag2); 0092 0093 // Valid tags with different IDs are not equal 0094 tag1 = Tag(1); 0095 tag2 = Tag(2); 0096 QVERIFY(tag1 != tag2); 0097 0098 // Valid tags with different IDs and equal GIDs are still not equal 0099 tag1.setGid("GID1"); 0100 tag2.setGid("GID1"); 0101 QVERIFY(tag1 != tag2); 0102 0103 // Valid tags with equal ID are equal regardless of GIDs 0104 tag2 = Tag(1); 0105 tag2.setGid("GID2"); 0106 QVERIFY(tag1 == tag2); 0107 } 0108 0109 void TagTest::testCreateFetch() 0110 { 0111 Tag tag; 0112 tag.setGid("gid"); 0113 tag.setType("mytype"); 0114 auto createjob = new TagCreateJob(tag, this); 0115 AKVERIFYEXEC(createjob); 0116 QVERIFY(createjob->tag().isValid()); 0117 0118 { 0119 auto fetchJob = new TagFetchJob(this); 0120 AKVERIFYEXEC(fetchJob); 0121 QCOMPARE(fetchJob->tags().size(), 1); 0122 QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); 0123 QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); 0124 0125 auto deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); 0126 AKVERIFYEXEC(deleteJob); 0127 } 0128 0129 { 0130 auto fetchJob = new TagFetchJob(this); 0131 AKVERIFYEXEC(fetchJob); 0132 QCOMPARE(fetchJob->tags().size(), 0); 0133 } 0134 } 0135 0136 void TagTest::testRID() 0137 { 0138 { 0139 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); 0140 AKVERIFYEXEC(select); 0141 } 0142 Tag tag; 0143 tag.setGid("gid"); 0144 tag.setType("mytype"); 0145 tag.setRemoteId("rid"); 0146 auto createjob = new TagCreateJob(tag, this); 0147 AKVERIFYEXEC(createjob); 0148 QVERIFY(createjob->tag().isValid()); 0149 0150 { 0151 auto fetchJob = new TagFetchJob(this); 0152 fetchJob->fetchScope().setFetchRemoteId(true); 0153 AKVERIFYEXEC(fetchJob); 0154 QCOMPARE(fetchJob->tags().size(), 1); 0155 QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); 0156 QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); 0157 QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid")); 0158 0159 auto deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); 0160 AKVERIFYEXEC(deleteJob); 0161 } 0162 { 0163 auto select = new ResourceSelectJob(QStringLiteral("")); 0164 AKVERIFYEXEC(select); 0165 } 0166 } 0167 0168 void TagTest::testRIDIsolation() 0169 { 0170 { 0171 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); 0172 AKVERIFYEXEC(select); 0173 } 0174 0175 Tag tag; 0176 tag.setGid("gid"); 0177 tag.setType("mytype"); 0178 tag.setRemoteId("rid_0"); 0179 0180 auto createJob = new TagCreateJob(tag, this); 0181 AKVERIFYEXEC(createJob); 0182 QVERIFY(createJob->tag().isValid()); 0183 0184 qint64 tagId; 0185 { 0186 auto fetchJob = new TagFetchJob(this); 0187 fetchJob->fetchScope().setFetchRemoteId(true); 0188 AKVERIFYEXEC(fetchJob); 0189 QCOMPARE(fetchJob->tags().count(), 1); 0190 QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); 0191 QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); 0192 QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid_0")); 0193 tagId = fetchJob->tags().first().id(); 0194 } 0195 0196 { 0197 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_1")); 0198 AKVERIFYEXEC(select); 0199 } 0200 0201 tag.setRemoteId("rid_1"); 0202 createJob = new TagCreateJob(tag, this); 0203 createJob->setMergeIfExisting(true); 0204 AKVERIFYEXEC(createJob); 0205 QVERIFY(createJob->tag().isValid()); 0206 0207 { 0208 auto fetchJob = new TagFetchJob(this); 0209 fetchJob->fetchScope().setFetchRemoteId(true); 0210 AKVERIFYEXEC(fetchJob); 0211 QCOMPARE(fetchJob->tags().count(), 1); 0212 QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); 0213 QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); 0214 QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid_1")); 0215 0216 QCOMPARE(fetchJob->tags().first().id(), tagId); 0217 } 0218 0219 auto deleteJob = new TagDeleteJob(Tag(tagId), this); 0220 AKVERIFYEXEC(deleteJob); 0221 0222 { 0223 auto select = new ResourceSelectJob(QStringLiteral("")); 0224 AKVERIFYEXEC(select); 0225 } 0226 } 0227 0228 void TagTest::testDelete() 0229 { 0230 Akonadi::Monitor monitor; 0231 monitor.setTypeMonitored(Monitor::Tags); 0232 QSignalSpy spy(&monitor, &Monitor::tagRemoved); 0233 0234 Tag tag1; 0235 { 0236 tag1.setGid("tag1"); 0237 auto createjob = new TagCreateJob(tag1, this); 0238 AKVERIFYEXEC(createjob); 0239 QVERIFY(createjob->tag().isValid()); 0240 tag1 = createjob->tag(); 0241 } 0242 Tag tag2; 0243 { 0244 tag2.setGid("tag2"); 0245 auto createjob = new TagCreateJob(tag2, this); 0246 AKVERIFYEXEC(createjob); 0247 QVERIFY(createjob->tag().isValid()); 0248 tag2 = createjob->tag(); 0249 } 0250 { 0251 auto deleteJob = new TagDeleteJob(tag1, this); 0252 AKVERIFYEXEC(deleteJob); 0253 } 0254 0255 { 0256 auto fetchJob = new TagFetchJob(this); 0257 AKVERIFYEXEC(fetchJob); 0258 QCOMPARE(fetchJob->tags().size(), 1); 0259 QCOMPARE(fetchJob->tags().first().gid(), tag2.gid()); 0260 } 0261 { 0262 auto deleteJob = new TagDeleteJob(tag2, this); 0263 AKVERIFYEXEC(deleteJob); 0264 } 0265 0266 // Collect Remove notification, so that they don't interfere with testDeleteRIDIsolation 0267 QTRY_VERIFY(!spy.isEmpty()); 0268 } 0269 0270 void TagTest::testDeleteRIDIsolation() 0271 { 0272 Tag tag; 0273 tag.setGid("gid"); 0274 tag.setType("mytype"); 0275 tag.setRemoteId("rid_0"); 0276 0277 { 0278 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); 0279 AKVERIFYEXEC(select); 0280 0281 auto createJob = new TagCreateJob(tag, this); 0282 AKVERIFYEXEC(createJob); 0283 QVERIFY(createJob->tag().isValid()); 0284 tag.setId(createJob->tag().id()); 0285 } 0286 0287 tag.setRemoteId("rid_1"); 0288 { 0289 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_1")); 0290 AKVERIFYEXEC(select); 0291 0292 auto createJob = new TagCreateJob(tag, this); 0293 createJob->setMergeIfExisting(true); 0294 AKVERIFYEXEC(createJob); 0295 QVERIFY(createJob->tag().isValid()); 0296 } 0297 0298 auto monitor = AkonadiTest::getTestMonitor(); 0299 QSignalSpy signalSpy(monitor.get(), &Monitor::tagRemoved); 0300 0301 auto deleteJob = new TagDeleteJob(tag, this); 0302 AKVERIFYEXEC(deleteJob); 0303 0304 // Other tests notifications might interfere due to notification compression on server 0305 QTRY_VERIFY(signalSpy.count() >= 1); 0306 0307 Tag removedTag; 0308 while (!signalSpy.isEmpty()) { 0309 const Tag t = signalSpy.takeFirst().takeFirst().value<Akonadi::Tag>(); 0310 if (t.id() == tag.id()) { 0311 removedTag = t; 0312 break; 0313 } 0314 } 0315 0316 QVERIFY(removedTag.isValid()); 0317 QVERIFY(removedTag.remoteId().isEmpty()); 0318 0319 { 0320 auto select = new ResourceSelectJob(QStringLiteral(""), this); 0321 AKVERIFYEXEC(select); 0322 } 0323 } 0324 0325 void TagTest::testModify() 0326 { 0327 Tag tag; 0328 { 0329 tag.setGid("gid"); 0330 auto createjob = new TagCreateJob(tag, this); 0331 AKVERIFYEXEC(createjob); 0332 QVERIFY(createjob->tag().isValid()); 0333 tag = createjob->tag(); 0334 } 0335 0336 // We can add an attribute 0337 { 0338 auto attr = tag.attribute<Akonadi::TagAttribute>(Tag::AddIfMissing); 0339 attr->setDisplayName(QStringLiteral("display name")); 0340 tag.setParent(Tag(0)); 0341 tag.setType("mytype"); 0342 auto modJob = new TagModifyJob(tag, this); 0343 AKVERIFYEXEC(modJob); 0344 0345 auto fetchJob = new TagFetchJob(this); 0346 fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>(); 0347 AKVERIFYEXEC(fetchJob); 0348 QCOMPARE(fetchJob->tags().size(), 1); 0349 QVERIFY(fetchJob->tags().first().hasAttribute<Akonadi::TagAttribute>()); 0350 } 0351 // We can update an attribute 0352 { 0353 auto attr = tag.attribute<Akonadi::TagAttribute>(Tag::AddIfMissing); 0354 attr->setDisplayName(QStringLiteral("display name2")); 0355 auto modJob = new TagModifyJob(tag, this); 0356 AKVERIFYEXEC(modJob); 0357 0358 auto fetchJob = new TagFetchJob(this); 0359 fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>(); 0360 AKVERIFYEXEC(fetchJob); 0361 QCOMPARE(fetchJob->tags().size(), 1); 0362 QVERIFY(fetchJob->tags().first().hasAttribute<Akonadi::TagAttribute>()); 0363 QCOMPARE(fetchJob->tags().first().attribute<Akonadi::TagAttribute>()->displayName(), attr->displayName()); 0364 } 0365 // We can clear an attribute 0366 { 0367 tag.removeAttribute<Akonadi::TagAttribute>(); 0368 auto modJob = new TagModifyJob(tag, this); 0369 AKVERIFYEXEC(modJob); 0370 0371 auto fetchJob = new TagFetchJob(this); 0372 fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>(); 0373 AKVERIFYEXEC(fetchJob); 0374 QCOMPARE(fetchJob->tags().size(), 1); 0375 QVERIFY(!fetchJob->tags().first().hasAttribute<Akonadi::TagAttribute>()); 0376 } 0377 0378 auto deleteJob = new TagDeleteJob(tag, this); 0379 AKVERIFYEXEC(deleteJob); 0380 } 0381 0382 void TagTest::testModifyFromResource() 0383 { 0384 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); 0385 AKVERIFYEXEC(select); 0386 0387 Tag tag; 0388 { 0389 tag.setGid("gid"); 0390 tag.setRemoteId("rid"); 0391 auto createjob = new TagCreateJob(tag, this); 0392 AKVERIFYEXEC(createjob); 0393 QVERIFY(createjob->tag().isValid()); 0394 tag = createjob->tag(); 0395 } 0396 0397 { 0398 tag.setRemoteId(QByteArray("")); 0399 auto modJob = new TagModifyJob(tag, this); 0400 AKVERIFYEXEC(modJob); 0401 0402 // The tag is removed on the server, because we just removed the last 0403 // RemoteID 0404 auto fetchJob = new TagFetchJob(this); 0405 AKVERIFYEXEC(fetchJob); 0406 QCOMPARE(fetchJob->tags().size(), 0); 0407 } 0408 } 0409 0410 void TagTest::testCreateMerge() 0411 { 0412 Tag tag; 0413 { 0414 tag.setGid("gid"); 0415 auto createjob = new TagCreateJob(tag, this); 0416 AKVERIFYEXEC(createjob); 0417 QVERIFY(createjob->tag().isValid()); 0418 tag = createjob->tag(); 0419 } 0420 { 0421 Tag tag2; 0422 tag2.setGid("gid"); 0423 auto createjob = new TagCreateJob(tag2, this); 0424 createjob->setMergeIfExisting(true); 0425 AKVERIFYEXEC(createjob); 0426 QVERIFY(createjob->tag().isValid()); 0427 QCOMPARE(createjob->tag().id(), tag.id()); 0428 } 0429 0430 auto deleteJob = new TagDeleteJob(tag, this); 0431 AKVERIFYEXEC(deleteJob); 0432 } 0433 0434 void TagTest::testAttributes() 0435 { 0436 Tag tag; 0437 { 0438 tag.setGid("gid2"); 0439 auto attr = tag.attribute<TagAttribute>(Tag::AddIfMissing); 0440 attr->setDisplayName(QStringLiteral("name")); 0441 attr->setInToolbar(true); 0442 auto createjob = new TagCreateJob(tag, this); 0443 AKVERIFYEXEC(createjob); 0444 QVERIFY(createjob->tag().isValid()); 0445 tag = createjob->tag(); 0446 0447 { 0448 auto fetchJob = new TagFetchJob(createjob->tag(), this); 0449 fetchJob->fetchScope().fetchAttribute<TagAttribute>(); 0450 AKVERIFYEXEC(fetchJob); 0451 QCOMPARE(fetchJob->tags().size(), 1); 0452 QVERIFY(fetchJob->tags().first().hasAttribute<TagAttribute>()); 0453 // we need to clone because the returned attribute is just a reference and destroyed on the next line 0454 // FIXME we should find a better solution for this (like returning a smart pointer or value object) 0455 QScopedPointer<TagAttribute> tagAttr(fetchJob->tags().first().attribute<TagAttribute>()->clone()); 0456 QVERIFY(tagAttr); 0457 QCOMPARE(tagAttr->displayName(), QStringLiteral("name")); 0458 QCOMPARE(tagAttr->inToolbar(), true); 0459 } 0460 } 0461 // Try fetching multiple items 0462 Tag tag2; 0463 { 0464 tag2.setGid("gid22"); 0465 TagAttribute *attr = tag.attribute<TagAttribute>(Tag::AddIfMissing)->clone(); 0466 attr->setDisplayName(QStringLiteral("name2")); 0467 attr->setInToolbar(true); 0468 tag2.addAttribute(attr); 0469 auto createjob = new TagCreateJob(tag2, this); 0470 AKVERIFYEXEC(createjob); 0471 QVERIFY(createjob->tag().isValid()); 0472 tag2 = createjob->tag(); 0473 0474 { 0475 auto fetchJob = new TagFetchJob(Tag::List() << tag << tag2, this); 0476 fetchJob->fetchScope().fetchAttribute<TagAttribute>(); 0477 AKVERIFYEXEC(fetchJob); 0478 QCOMPARE(fetchJob->tags().size(), 2); 0479 QVERIFY(fetchJob->tags().at(0).hasAttribute<TagAttribute>()); 0480 QVERIFY(fetchJob->tags().at(1).hasAttribute<TagAttribute>()); 0481 } 0482 } 0483 0484 auto deleteJob = new TagDeleteJob(Tag::List() << tag << tag2, this); 0485 AKVERIFYEXEC(deleteJob); 0486 } 0487 0488 void TagTest::testTagItem() 0489 { 0490 Akonadi::Monitor monitor; 0491 monitor.itemFetchScope().setFetchTags(true); 0492 monitor.setAllMonitored(true); 0493 QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); 0494 0495 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0496 Tag tag; 0497 { 0498 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); 0499 AKVERIFYEXEC(createjob); 0500 tag = createjob->tag(); 0501 } 0502 0503 Item item1; 0504 { 0505 item1.setMimeType(QStringLiteral("application/octet-stream")); 0506 auto append = new ItemCreateJob(item1, res3, this); 0507 AKVERIFYEXEC(append); 0508 item1 = append->item(); 0509 } 0510 0511 item1.setTag(tag); 0512 0513 QSignalSpy tagsSpy(&monitor, &Monitor::itemsTagsChanged); 0514 0515 auto modJob = new ItemModifyJob(item1, this); 0516 AKVERIFYEXEC(modJob); 0517 0518 QTRY_VERIFY(tagsSpy.count() >= 1); 0519 QTRY_COMPARE(tagsSpy.last().first().value<Akonadi::Item::List>().first().id(), item1.id()); 0520 QTRY_COMPARE(tagsSpy.last().at(1).value<QSet<Tag>>().size(), 1); // 1 added tag 0521 0522 auto fetchJob = new ItemFetchJob(item1, this); 0523 fetchJob->fetchScope().setFetchTags(true); 0524 AKVERIFYEXEC(fetchJob); 0525 QCOMPARE(fetchJob->items().first().tags().size(), 1); 0526 0527 auto deleteJob = new TagDeleteJob(tag, this); 0528 AKVERIFYEXEC(deleteJob); 0529 } 0530 0531 void TagTest::testCreateItem() 0532 { 0533 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0534 Tag tag; 0535 { 0536 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); 0537 AKVERIFYEXEC(createjob); 0538 tag = createjob->tag(); 0539 } 0540 0541 Item item1; 0542 { 0543 item1.setMimeType(QStringLiteral("application/octet-stream")); 0544 item1.setTag(tag); 0545 auto append = new ItemCreateJob(item1, res3, this); 0546 AKVERIFYEXEC(append); 0547 item1 = append->item(); 0548 } 0549 0550 auto fetchJob = new ItemFetchJob(item1, this); 0551 fetchJob->fetchScope().setFetchTags(true); 0552 AKVERIFYEXEC(fetchJob); 0553 QCOMPARE(fetchJob->items().first().tags().size(), 1); 0554 0555 auto deleteJob = new TagDeleteJob(tag, this); 0556 AKVERIFYEXEC(deleteJob); 0557 } 0558 0559 void TagTest::testCreateItemWithTags() 0560 { 0561 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0562 Tag tag1; 0563 { 0564 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); 0565 AKVERIFYEXEC(createjob); 0566 tag1 = createjob->tag(); 0567 } 0568 Tag tag2; 0569 { 0570 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid2")), this); 0571 AKVERIFYEXEC(createjob); 0572 tag2 = createjob->tag(); 0573 } 0574 0575 Item item1; 0576 { 0577 item1.setMimeType(QStringLiteral("application/octet-stream")); 0578 item1.setTags({tag1, tag2}); 0579 auto append = new ItemCreateJob(item1, res3, this); 0580 AKVERIFYEXEC(append); 0581 item1 = append->item(); 0582 } 0583 0584 auto fetchJob = new ItemFetchJob(item1, this); 0585 fetchJob->fetchScope().setFetchTags(true); 0586 AKVERIFYEXEC(fetchJob); 0587 auto fetchTags = fetchJob->items().first().tags(); 0588 0589 std::unique_ptr<TagDeleteJob, void (*)(TagDeleteJob *)> finally(new TagDeleteJob({tag1, tag2}, this), [](TagDeleteJob *j) { 0590 j->exec(); 0591 delete j; 0592 }); 0593 QCOMPARE(fetchTags.size(), 2); 0594 QVERIFY(fetchTags.contains(tag1)); 0595 QVERIFY(fetchTags.contains(tag2)); 0596 } 0597 0598 void TagTest::testFetchTagIdWithItem() 0599 { 0600 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0601 Tag tag; 0602 { 0603 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); 0604 AKVERIFYEXEC(createjob); 0605 tag = createjob->tag(); 0606 } 0607 0608 Item item1; 0609 { 0610 item1.setMimeType(QStringLiteral("application/octet-stream")); 0611 item1.setTag(tag); 0612 auto append = new ItemCreateJob(item1, res3, this); 0613 AKVERIFYEXEC(append); 0614 item1 = append->item(); 0615 } 0616 0617 auto fetchJob = new ItemFetchJob(item1, this); 0618 fetchJob->fetchScope().setFetchTags(true); 0619 fetchJob->fetchScope().tagFetchScope().setFetchIdOnly(true); 0620 AKVERIFYEXEC(fetchJob); 0621 QCOMPARE(fetchJob->items().first().tags().size(), 1); 0622 Tag t = fetchJob->items().first().tags().first(); 0623 QCOMPARE(t.id(), tag.id()); 0624 QVERIFY(t.gid().isEmpty()); 0625 0626 auto deleteJob = new TagDeleteJob(tag, this); 0627 AKVERIFYEXEC(deleteJob); 0628 } 0629 0630 void TagTest::testFetchFullTagWithItem() 0631 { 0632 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0633 Tag tag; 0634 { 0635 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); 0636 AKVERIFYEXEC(createjob); 0637 tag = createjob->tag(); 0638 } 0639 0640 Item item1; 0641 { 0642 item1.setMimeType(QStringLiteral("application/octet-stream")); 0643 auto append = new ItemCreateJob(item1, res3, this); 0644 AKVERIFYEXEC(append); 0645 item1 = append->item(); 0646 // FIXME This should also be possible with create, but isn't 0647 item1.setTag(tag); 0648 } 0649 0650 auto modJob = new ItemModifyJob(item1, this); 0651 AKVERIFYEXEC(modJob); 0652 0653 auto fetchJob = new ItemFetchJob(item1, this); 0654 fetchJob->fetchScope().setFetchTags(true); 0655 fetchJob->fetchScope().tagFetchScope().setFetchIdOnly(false); 0656 AKVERIFYEXEC(fetchJob); 0657 QCOMPARE(fetchJob->items().first().tags().size(), 1); 0658 Tag t = fetchJob->items().first().tags().first(); 0659 QCOMPARE(t, tag); 0660 QVERIFY(!t.gid().isEmpty()); 0661 0662 auto deleteJob = new TagDeleteJob(tag, this); 0663 AKVERIFYEXEC(deleteJob); 0664 } 0665 0666 void TagTest::testModifyItemWithTagByGID() 0667 { 0668 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0669 { 0670 Tag tag; 0671 tag.setGid("gid2"); 0672 auto createjob = new TagCreateJob(tag, this); 0673 AKVERIFYEXEC(createjob); 0674 } 0675 0676 Item item1; 0677 { 0678 item1.setMimeType(QStringLiteral("application/octet-stream")); 0679 auto append = new ItemCreateJob(item1, res3, this); 0680 AKVERIFYEXEC(append); 0681 item1 = append->item(); 0682 } 0683 0684 Tag tag; 0685 tag.setGid("gid2"); 0686 item1.setTag(tag); 0687 0688 auto modJob = new ItemModifyJob(item1, this); 0689 AKVERIFYEXEC(modJob); 0690 0691 auto fetchJob = new ItemFetchJob(item1, this); 0692 fetchJob->fetchScope().setFetchTags(true); 0693 AKVERIFYEXEC(fetchJob); 0694 QCOMPARE(fetchJob->items().first().tags().size(), 1); 0695 0696 auto deleteJob = new TagDeleteJob(fetchJob->items().first().tags().first(), this); 0697 AKVERIFYEXEC(deleteJob); 0698 } 0699 0700 void TagTest::testModifyItemWithTagByRID() 0701 { 0702 { 0703 auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); 0704 AKVERIFYEXEC(select); 0705 } 0706 0707 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0708 Tag tag3; 0709 { 0710 tag3.setGid("gid3"); 0711 tag3.setRemoteId("rid3"); 0712 auto createjob = new TagCreateJob(tag3, this); 0713 AKVERIFYEXEC(createjob); 0714 tag3 = createjob->tag(); 0715 } 0716 0717 Item item1; 0718 { 0719 item1.setMimeType(QStringLiteral("application/octet-stream")); 0720 auto append = new ItemCreateJob(item1, res3, this); 0721 AKVERIFYEXEC(append); 0722 item1 = append->item(); 0723 } 0724 0725 Tag tag; 0726 tag.setRemoteId("rid2"); 0727 item1.setTag(tag); 0728 0729 auto modJob = new ItemModifyJob(item1, this); 0730 AKVERIFYEXEC(modJob); 0731 0732 auto fetchJob = new ItemFetchJob(item1, this); 0733 fetchJob->fetchScope().setFetchTags(true); 0734 AKVERIFYEXEC(fetchJob); 0735 QCOMPARE(fetchJob->items().first().tags().size(), 1); 0736 0737 { 0738 auto deleteJob = new TagDeleteJob(fetchJob->items().first().tags().first(), this); 0739 AKVERIFYEXEC(deleteJob); 0740 } 0741 0742 { 0743 auto deleteJob = new TagDeleteJob(tag3, this); 0744 AKVERIFYEXEC(deleteJob); 0745 } 0746 0747 { 0748 auto select = new ResourceSelectJob(QStringLiteral("")); 0749 AKVERIFYEXEC(select); 0750 } 0751 } 0752 0753 void TagTest::testMonitor() 0754 { 0755 Akonadi::Monitor monitor; 0756 monitor.setTypeMonitored(Akonadi::Monitor::Tags); 0757 monitor.tagFetchScope().fetchAttribute<Akonadi::TagAttribute>(); 0758 QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); 0759 0760 Akonadi::Tag createdTag; 0761 { 0762 QSignalSpy addedSpy(&monitor, &Monitor::tagAdded); 0763 QVERIFY(addedSpy.isValid()); 0764 Tag tag; 0765 tag.setGid("gid2"); 0766 tag.setName(QStringLiteral("name2")); 0767 tag.setType("type2"); 0768 auto createjob = new TagCreateJob(tag, this); 0769 AKVERIFYEXEC(createjob); 0770 createdTag = createjob->tag(); 0771 QCOMPARE(createdTag.type(), tag.type()); 0772 QCOMPARE(createdTag.name(), tag.name()); 0773 QCOMPARE(createdTag.gid(), tag.gid()); 0774 // We usually pick up signals from the previous tests as well (due to server-side notification caching) 0775 QTRY_VERIFY(addedSpy.count() >= 1); 0776 QTRY_COMPARE(addedSpy.last().first().value<Akonadi::Tag>().id(), createdTag.id()); 0777 const auto notifiedTag = addedSpy.last().first().value<Akonadi::Tag>(); 0778 QCOMPARE(notifiedTag.type(), createdTag.type()); 0779 QCOMPARE(notifiedTag.gid(), createdTag.gid()); 0780 QVERIFY(notifiedTag.hasAttribute<Akonadi::TagAttribute>()); 0781 QCOMPARE(notifiedTag.name(), createdTag.name()); // requires the TagAttribute 0782 } 0783 0784 { 0785 QSignalSpy modifiedSpy(&monitor, &Monitor::tagChanged); 0786 QVERIFY(modifiedSpy.isValid()); 0787 createdTag.setName(QStringLiteral("name3")); 0788 0789 auto modJob = new TagModifyJob(createdTag, this); 0790 AKVERIFYEXEC(modJob); 0791 // We usually pick up signals from the previous tests as well (due to server-side notification caching) 0792 QTRY_VERIFY(modifiedSpy.count() >= 1); 0793 QTRY_COMPARE(modifiedSpy.last().first().value<Akonadi::Tag>().id(), createdTag.id()); 0794 const auto notifiedTag = modifiedSpy.last().first().value<Akonadi::Tag>(); 0795 QCOMPARE(notifiedTag.type(), createdTag.type()); 0796 QCOMPARE(notifiedTag.gid(), createdTag.gid()); 0797 QVERIFY(notifiedTag.hasAttribute<Akonadi::TagAttribute>()); 0798 QCOMPARE(notifiedTag.name(), createdTag.name()); // requires the TagAttribute 0799 } 0800 0801 { 0802 QSignalSpy removedSpy(&monitor, &Monitor::tagRemoved); 0803 QVERIFY(removedSpy.isValid()); 0804 auto deletejob = new TagDeleteJob(createdTag, this); 0805 AKVERIFYEXEC(deletejob); 0806 QTRY_VERIFY(removedSpy.count() >= 1); 0807 QTRY_COMPARE(removedSpy.last().first().value<Akonadi::Tag>().id(), createdTag.id()); 0808 const auto notifiedTag = removedSpy.last().first().value<Akonadi::Tag>(); 0809 QCOMPARE(notifiedTag.type(), createdTag.type()); 0810 QCOMPARE(notifiedTag.gid(), createdTag.gid()); 0811 QVERIFY(notifiedTag.hasAttribute<Akonadi::TagAttribute>()); 0812 QCOMPARE(notifiedTag.name(), createdTag.name()); // requires the TagAttribute 0813 } 0814 } 0815 0816 void TagTest::testTagAttributeConfusionBug() 0817 { 0818 // Create two tags 0819 Tag firstTag; 0820 { 0821 firstTag.setGid("gid"); 0822 firstTag.setName(QStringLiteral("display name")); 0823 auto createjob = new TagCreateJob(firstTag, this); 0824 AKVERIFYEXEC(createjob); 0825 QVERIFY(createjob->tag().isValid()); 0826 firstTag = createjob->tag(); 0827 } 0828 Tag secondTag; 0829 { 0830 secondTag.setGid("AnotherGID"); 0831 secondTag.setName(QStringLiteral("another name")); 0832 auto createjob = new TagCreateJob(secondTag, this); 0833 AKVERIFYEXEC(createjob); 0834 QVERIFY(createjob->tag().isValid()); 0835 secondTag = createjob->tag(); 0836 } 0837 0838 Akonadi::Monitor monitor; 0839 monitor.setTypeMonitored(Akonadi::Monitor::Tags); 0840 QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady)); 0841 0842 const QList<Tag::Id> firstTagIdList{firstTag.id()}; 0843 0844 // Modify attribute on the first tag 0845 // and check the notification 0846 { 0847 QSignalSpy modifiedSpy(&monitor, &Akonadi::Monitor::tagChanged); 0848 0849 firstTag.setName(QStringLiteral("renamed")); 0850 auto modJob = new TagModifyJob(firstTag, this); 0851 AKVERIFYEXEC(modJob); 0852 0853 auto fetchJob = new TagFetchJob(firstTagIdList, this); 0854 QVERIFY(fetchJob->fetchScope().fetchAllAttributes()); 0855 AKVERIFYEXEC(fetchJob); 0856 QCOMPARE(fetchJob->tags().size(), 1); 0857 QCOMPARE(fetchJob->tags().first().name(), firstTag.name()); 0858 0859 QTRY_VERIFY(modifiedSpy.count() >= 1); 0860 QTRY_COMPARE(modifiedSpy.last().first().value<Akonadi::Tag>().id(), firstTag.id()); 0861 const auto notifiedTag = modifiedSpy.last().first().value<Akonadi::Tag>(); 0862 QCOMPARE(notifiedTag.name(), firstTag.name()); 0863 } 0864 0865 // Cleanup 0866 auto deleteJob = new TagDeleteJob(firstTag, this); 0867 AKVERIFYEXEC(deleteJob); 0868 auto anotherDeleteJob = new TagDeleteJob(secondTag, this); 0869 AKVERIFYEXEC(anotherDeleteJob); 0870 } 0871 0872 void TagTest::testFetchItemsByTag() 0873 { 0874 const Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3"))); 0875 Tag tag; 0876 { 0877 auto createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); 0878 AKVERIFYEXEC(createjob); 0879 tag = createjob->tag(); 0880 } 0881 0882 Item item1; 0883 { 0884 item1.setMimeType(QStringLiteral("application/octet-stream")); 0885 auto append = new ItemCreateJob(item1, res3, this); 0886 AKVERIFYEXEC(append); 0887 item1 = append->item(); 0888 // FIXME This should also be possible with create, but isn't 0889 item1.setTag(tag); 0890 } 0891 0892 auto modJob = new ItemModifyJob(item1, this); 0893 AKVERIFYEXEC(modJob); 0894 0895 auto fetchJob = new ItemFetchJob(tag, this); 0896 AKVERIFYEXEC(fetchJob); 0897 QCOMPARE(fetchJob->items().size(), 1); 0898 Item i = fetchJob->items().first(); 0899 QCOMPARE(i, item1); 0900 0901 auto deleteJob = new TagDeleteJob(tag, this); 0902 AKVERIFYEXEC(deleteJob); 0903 } 0904 0905 void TagTest::tagModifyJobShouldOnlySendModifiedAttributes() 0906 { 0907 // Given a tag with an attribute 0908 Tag tag(QStringLiteral("tagWithAttr")); 0909 auto attr = new Akonadi::TagAttribute; 0910 attr->setDisplayName(QStringLiteral("display name")); 0911 tag.addAttribute(attr); 0912 { 0913 auto createjob = new TagCreateJob(tag, this); 0914 AKVERIFYEXEC(createjob); 0915 tag = createjob->tag(); 0916 } 0917 0918 // When one job modifies this attribute, and another one does an unrelated modify job 0919 Tag attrModTag(tag.id()); 0920 auto modAttr = attrModTag.attribute<Akonadi::TagAttribute>(Tag::AddIfMissing); 0921 modAttr->setDisplayName(QStringLiteral("modified")); 0922 auto attrModJob = new TagModifyJob(attrModTag, this); 0923 AKVERIFYEXEC(attrModJob); 0924 0925 tag.setType(Tag::GENERIC); 0926 // this job shouldn't send the old attribute again 0927 auto modJob = new TagModifyJob(tag, this); 0928 AKVERIFYEXEC(modJob); 0929 0930 // Then the tag should have both the modified attribute and the modified type 0931 { 0932 auto fetchJob = new TagFetchJob(this); 0933 fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>(); 0934 AKVERIFYEXEC(fetchJob); 0935 QCOMPARE(fetchJob->tags().size(), 1); 0936 const Tag fetchedTag = fetchJob->tags().at(0); 0937 QVERIFY(fetchedTag.hasAttribute<Akonadi::TagAttribute>()); 0938 QCOMPARE(fetchedTag.attribute<Akonadi::TagAttribute>()->displayName(), QStringLiteral("modified")); 0939 QCOMPARE(fetchedTag.type(), Tag::GENERIC); 0940 } 0941 0942 // And when adding a new attribute next to the old one 0943 auto attr2 = AttributeFactory::createAttribute("SecondType"); 0944 tag.addAttribute(attr2); 0945 // this job shouldn't send the old attribute again 0946 auto modJob2 = new TagModifyJob(tag, this); 0947 AKVERIFYEXEC(modJob2); 0948 0949 // Then the tag should have the modified attribute and the second one 0950 { 0951 auto fetchJob = new TagFetchJob(this); 0952 fetchJob->fetchScope().setFetchAllAttributes(true); 0953 AKVERIFYEXEC(fetchJob); 0954 QCOMPARE(fetchJob->tags().size(), 1); 0955 const Tag fetchedTag = fetchJob->tags().at(0); 0956 QVERIFY(fetchedTag.hasAttribute<Akonadi::TagAttribute>()); 0957 QCOMPARE(fetchedTag.attribute<Akonadi::TagAttribute>()->displayName(), QStringLiteral("modified")); 0958 QCOMPARE(fetchedTag.type(), Tag::GENERIC); 0959 QVERIFY(fetchedTag.attribute("SecondType")); 0960 } 0961 } 0962 0963 #include "tagtest.moc" 0964 0965 QTEST_AKONADIMAIN(TagTest)