File indexing completed on 2024-11-10 04:40:22
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 <storage/selectquerybuilder.h> 0010 0011 #include "aktest.h" 0012 #include "dbinitializer.h" 0013 #include "entities.h" 0014 #include "fakeakonadiserver.h" 0015 0016 #include <QTest> 0017 0018 using namespace Akonadi; 0019 using namespace Akonadi::Server; 0020 0021 Q_DECLARE_METATYPE(Akonadi::Server::Relation::List) 0022 Q_DECLARE_METATYPE(Akonadi::Server::Relation) 0023 0024 static Protocol::ChangeNotificationList extractNotifications(const QSharedPointer<QSignalSpy> ¬ificationSpy) 0025 { 0026 Protocol::ChangeNotificationList receivedNotifications; 0027 for (int q = 0; q < notificationSpy->size(); q++) { 0028 // Only one notify call 0029 if (notificationSpy->at(q).count() != 1) { 0030 qWarning() << "Error: We're assuming only one notify call."; 0031 return Protocol::ChangeNotificationList(); 0032 } 0033 const Protocol::ChangeNotificationList n = notificationSpy->at(q).first().value<Protocol::ChangeNotificationList>(); 0034 for (int i = 0; i < n.size(); i++) { 0035 // qDebug() << n.at(i); 0036 receivedNotifications.append(n.at(i)); 0037 } 0038 } 0039 return receivedNotifications; 0040 } 0041 0042 class RelationHandlerTest : public QObject 0043 { 0044 Q_OBJECT 0045 0046 FakeAkonadiServer mAkonadi; 0047 0048 public: 0049 RelationHandlerTest() 0050 : QObject() 0051 { 0052 qRegisterMetaType<Akonadi::Server::Relation::List>(); 0053 0054 mAkonadi.setPopulateDb(false); 0055 mAkonadi.init(); 0056 0057 RelationType type; 0058 type.setName(QStringLiteral("type")); 0059 type.insert(); 0060 0061 RelationType type2; 0062 type2.setName(QStringLiteral("type2")); 0063 type2.insert(); 0064 } 0065 0066 QScopedPointer<DbInitializer> initializer; 0067 0068 Protocol::RelationChangeNotificationPtr relationNotification(Protocol::RelationChangeNotification::Operation op, 0069 const PimItem &item1, 0070 const PimItem &item2, 0071 const QString &rid, 0072 const QString &type = QStringLiteral("type")) 0073 { 0074 auto notification = Protocol::RelationChangeNotificationPtr::create(); 0075 notification->setOperation(op); 0076 notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0077 Protocol::FetchRelationsResponse relation; 0078 relation.setLeft(item1.id()); 0079 relation.setLeftMimeType(item1.mimeType().name().toLatin1()); 0080 relation.setRight(item2.id()); 0081 relation.setRightMimeType(item2.mimeType().name().toLatin1()); 0082 relation.setRemoteId(rid.toLatin1()); 0083 relation.setType(type.toLatin1()); 0084 notification->setRelation(std::move(relation)); 0085 return notification; 0086 } 0087 0088 private Q_SLOTS: 0089 void testStoreRelation_data() 0090 { 0091 initializer.reset(new DbInitializer); 0092 Resource res = initializer->createResource("testresource"); 0093 Collection col1 = initializer->createCollection("col1"); 0094 PimItem item1 = initializer->createItem("item1", col1); 0095 PimItem item2 = initializer->createItem("item2", col1); 0096 0097 QTest::addColumn<TestScenario::List>("scenarios"); 0098 QTest::addColumn<Relation::List>("expectedRelations"); 0099 QTest::addColumn<Protocol::ChangeNotificationList>("expectedNotifications"); 0100 0101 { 0102 TestScenario::List scenarios; 0103 scenarios << FakeAkonadiServer::loginScenario() 0104 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::ModifyRelationCommandPtr::create(item1.id(), item2.id(), "type")) 0105 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyRelationResponsePtr::create()); 0106 0107 Relation rel; 0108 rel.setLeftId(item1.id()); 0109 rel.setRightId(item2.id()); 0110 RelationType type; 0111 type.setName(QStringLiteral("type")); 0112 rel.setRelationType(type); 0113 0114 auto itemNotification = Protocol::ItemChangeNotificationPtr::create(); 0115 itemNotification->setOperation(Protocol::ItemChangeNotification::ModifyRelations); 0116 itemNotification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0117 itemNotification->setResource("testresource"); 0118 itemNotification->setParentCollection(col1.id()); 0119 itemNotification->setItems({*initializer->fetchResponse(item1), *initializer->fetchResponse(item2)}); 0120 itemNotification->setAddedRelations({Protocol::ItemChangeNotification::Relation(item1.id(), item2.id(), QStringLiteral("type"))}); 0121 0122 const auto notification = relationNotification(Protocol::RelationChangeNotification::Add, item1, item2, rel.remoteId()); 0123 0124 QTest::newRow("uid create relation") << scenarios << (Relation::List() << rel) 0125 << (Protocol::ChangeNotificationList() << notification << itemNotification); 0126 } 0127 } 0128 0129 void testStoreRelation() 0130 { 0131 QFETCH(TestScenario::List, scenarios); 0132 QFETCH(Relation::List, expectedRelations); 0133 QFETCH(Protocol::ChangeNotificationList, expectedNotifications); 0134 0135 mAkonadi.setScenarios(scenarios); 0136 mAkonadi.runTest(); 0137 0138 auto notificationSpy = mAkonadi.notificationSpy(); 0139 QTRY_COMPARE(notificationSpy->empty(), expectedNotifications.empty()); 0140 const auto receivedNotifications = extractNotifications(notificationSpy); 0141 QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); 0142 for (int i = 0; i < expectedNotifications.size(); i++) { 0143 QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); 0144 } 0145 0146 const Relation::List relations = Relation::retrieveAll(); 0147 // Q_FOREACH (const Relation &rel, relations) { 0148 // akDebug() << rel.leftId() << rel.rightId(); 0149 // } 0150 QCOMPARE(relations.size(), expectedRelations.size()); 0151 for (int i = 0; i < relations.size(); i++) { 0152 QCOMPARE(relations.at(i).leftId(), expectedRelations.at(i).leftId()); 0153 QCOMPARE(relations.at(i).rightId(), expectedRelations.at(i).rightId()); 0154 // QCOMPARE(relations.at(i).typeId(), expectedRelations.at(i).typeId()); 0155 QCOMPARE(relations.at(i).remoteId(), expectedRelations.at(i).remoteId()); 0156 } 0157 QueryBuilder qb(Relation::tableName(), QueryBuilder::Delete); 0158 qb.exec(); 0159 } 0160 0161 void testRemoveRelation_data() 0162 { 0163 initializer.reset(new DbInitializer); 0164 QCOMPARE(Relation::retrieveAll().size(), 0); 0165 Resource res = initializer->createResource("testresource"); 0166 Collection col1 = initializer->createCollection("col1"); 0167 PimItem item1 = initializer->createItem("item1", col1); 0168 PimItem item2 = initializer->createItem("item2", col1); 0169 0170 Relation rel; 0171 rel.setLeftId(item1.id()); 0172 rel.setRightId(item2.id()); 0173 rel.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); 0174 QVERIFY(rel.insert()); 0175 0176 Relation rel2; 0177 rel2.setLeftId(item1.id()); 0178 rel2.setRightId(item2.id()); 0179 rel2.setRelationType(RelationType::retrieveByName(QStringLiteral("type2"))); 0180 QVERIFY(rel2.insert()); 0181 0182 QTest::addColumn<TestScenario::List>("scenarios"); 0183 QTest::addColumn<Relation::List>("expectedRelations"); 0184 QTest::addColumn<Protocol::ChangeNotificationList>("expectedNotifications"); 0185 { 0186 TestScenario::List scenarios; 0187 scenarios << FakeAkonadiServer::loginScenario() 0188 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::RemoveRelationsCommandPtr::create(item1.id(), item2.id(), "type")) 0189 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::RemoveRelationsResponsePtr::create()); 0190 0191 auto itemNotification = Protocol::ItemChangeNotificationPtr::create(); 0192 itemNotification->setOperation(Protocol::ItemChangeNotification::ModifyRelations); 0193 itemNotification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0194 itemNotification->setResource("testresource"); 0195 itemNotification->setParentCollection(col1.id()); 0196 itemNotification->setItems({*initializer->fetchResponse(item1), *initializer->fetchResponse(item2)}); 0197 itemNotification->setRemovedRelations({Protocol::ItemChangeNotification::Relation(item1.id(), item2.id(), QStringLiteral("type"))}); 0198 0199 const auto notification = relationNotification(Protocol::RelationChangeNotification::Remove, item1, item2, rel.remoteId()); 0200 0201 QTest::newRow("uid remove relation") << scenarios << (Relation::List() << rel2) 0202 << (Protocol::ChangeNotificationList() << notification << itemNotification); 0203 } 0204 0205 { 0206 TestScenario::List scenarios; 0207 scenarios << FakeAkonadiServer::loginScenario() 0208 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::RemoveRelationsCommandPtr::create(item1.id(), item2.id())) 0209 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::RemoveRelationsResponsePtr::create()); 0210 0211 auto itemNotification = Protocol::ItemChangeNotificationPtr::create(); 0212 itemNotification->setOperation(Protocol::ItemChangeNotification::ModifyRelations); 0213 itemNotification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0214 itemNotification->setResource("testresource"); 0215 itemNotification->setParentCollection(col1.id()); 0216 itemNotification->setItems({*initializer->fetchResponse(item1), *initializer->fetchResponse(item2)}); 0217 itemNotification->setRemovedRelations({Protocol::ItemChangeNotification::Relation(item1.id(), item2.id(), QStringLiteral("type2"))}); 0218 0219 const auto notification = relationNotification(Protocol::RelationChangeNotification::Remove, item1, item2, rel.remoteId(), QStringLiteral("type2")); 0220 0221 QTest::newRow("uid remove relation without type") 0222 << scenarios << Relation::List() << (Protocol::ChangeNotificationList() << notification << itemNotification); 0223 } 0224 } 0225 0226 void testRemoveRelation() 0227 { 0228 QFETCH(TestScenario::List, scenarios); 0229 QFETCH(Relation::List, expectedRelations); 0230 QFETCH(Protocol::ChangeNotificationList, expectedNotifications); 0231 0232 mAkonadi.setScenarios(scenarios); 0233 mAkonadi.runTest(); 0234 0235 auto notificationSpy = mAkonadi.notificationSpy(); 0236 QTRY_COMPARE(notificationSpy->empty(), expectedNotifications.empty()); 0237 const auto receivedNotifications = extractNotifications(notificationSpy); 0238 QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); 0239 for (int i = 0; i < expectedNotifications.size(); i++) { 0240 QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); 0241 } 0242 0243 const Relation::List relations = Relation::retrieveAll(); 0244 // Q_FOREACH (const Relation &rel, relations) { 0245 // akDebug() << rel.leftId() << rel.rightId() << rel.relationType().name() << rel.remoteId(); 0246 // } 0247 QCOMPARE(relations.size(), expectedRelations.size()); 0248 for (int i = 0; i < relations.size(); i++) { 0249 QCOMPARE(relations.at(i).leftId(), expectedRelations.at(i).leftId()); 0250 QCOMPARE(relations.at(i).rightId(), expectedRelations.at(i).rightId()); 0251 QCOMPARE(relations.at(i).typeId(), expectedRelations.at(i).typeId()); 0252 QCOMPARE(relations.at(i).remoteId(), expectedRelations.at(i).remoteId()); 0253 } 0254 } 0255 0256 void testListRelation_data() 0257 { 0258 QueryBuilder qb(Relation::tableName(), QueryBuilder::Delete); 0259 qb.exec(); 0260 0261 initializer.reset(new DbInitializer); 0262 QCOMPARE(Relation::retrieveAll().size(), 0); 0263 Resource res = initializer->createResource("testresource"); 0264 Collection col1 = initializer->createCollection("col1"); 0265 PimItem item1 = initializer->createItem("item1", col1); 0266 PimItem item2 = initializer->createItem("item2", col1); 0267 PimItem item3 = initializer->createItem("item3", col1); 0268 PimItem item4 = initializer->createItem("item4", col1); 0269 0270 Relation rel; 0271 rel.setLeftId(item1.id()); 0272 rel.setRightId(item2.id()); 0273 rel.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); 0274 rel.setRemoteId(QStringLiteral("foobar1")); 0275 QVERIFY(rel.insert()); 0276 0277 Relation rel2; 0278 rel2.setLeftId(item1.id()); 0279 rel2.setRightId(item2.id()); 0280 rel2.setRelationType(RelationType::retrieveByName(QStringLiteral("type2"))); 0281 rel2.setRemoteId(QStringLiteral("foobar2")); 0282 QVERIFY(rel2.insert()); 0283 0284 Relation rel3; 0285 rel3.setLeftId(item3.id()); 0286 rel3.setRightId(item4.id()); 0287 rel3.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); 0288 rel3.setRemoteId(QStringLiteral("foobar3")); 0289 QVERIFY(rel3.insert()); 0290 0291 Relation rel4; 0292 rel4.setLeftId(item4.id()); 0293 rel4.setRightId(item3.id()); 0294 rel4.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); 0295 rel4.setRemoteId(QStringLiteral("foobar4")); 0296 QVERIFY(rel4.insert()); 0297 0298 QTest::addColumn<TestScenario::List>("scenarios"); 0299 { 0300 TestScenario::List scenarios; 0301 scenarios << FakeAkonadiServer::loginScenario() 0302 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(-1, QList<QByteArray>{"type"})) 0303 << TestScenario::create(5, 0304 TestScenario::ServerCmd, 0305 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0306 item1.mimeType().name().toUtf8(), 0307 item2.id(), 0308 item2.mimeType().name().toUtf8(), 0309 "type", 0310 "foobar1")) 0311 << TestScenario::create(5, 0312 TestScenario::ServerCmd, 0313 Protocol::FetchRelationsResponsePtr::create(item3.id(), 0314 item3.mimeType().name().toUtf8(), 0315 item4.id(), 0316 item4.mimeType().name().toUtf8(), 0317 "type", 0318 "foobar3")) 0319 << TestScenario::create(5, 0320 TestScenario::ServerCmd, 0321 Protocol::FetchRelationsResponsePtr::create(item4.id(), 0322 item4.mimeType().name().toUtf8(), 0323 item3.id(), 0324 item3.mimeType().name().toUtf8(), 0325 "type", 0326 "foobar4")) 0327 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0328 0329 QTest::newRow("filter by type") << scenarios; 0330 } 0331 { 0332 TestScenario::List scenarios; 0333 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create()) 0334 << TestScenario::create(5, 0335 TestScenario::ServerCmd, 0336 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0337 item1.mimeType().name().toUtf8(), 0338 item2.id(), 0339 item2.mimeType().name().toUtf8(), 0340 "type", 0341 "foobar1")) 0342 << TestScenario::create(5, 0343 TestScenario::ServerCmd, 0344 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0345 item1.mimeType().name().toUtf8(), 0346 item2.id(), 0347 item2.mimeType().name().toUtf8(), 0348 "type2", 0349 "foobar2")) 0350 << TestScenario::create(5, 0351 TestScenario::ServerCmd, 0352 Protocol::FetchRelationsResponsePtr::create(item3.id(), 0353 item3.mimeType().name().toUtf8(), 0354 item4.id(), 0355 item4.mimeType().name().toUtf8(), 0356 "type", 0357 "foobar3")) 0358 << TestScenario::create(5, 0359 TestScenario::ServerCmd, 0360 Protocol::FetchRelationsResponsePtr::create(item4.id(), 0361 item4.mimeType().name().toUtf8(), 0362 item3.id(), 0363 item3.mimeType().name().toUtf8(), 0364 "type", 0365 "foobar4")) 0366 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0367 0368 QTest::newRow("no filter") << scenarios; 0369 } 0370 { 0371 TestScenario::List scenarios; 0372 scenarios << FakeAkonadiServer::loginScenario() 0373 << TestScenario::create(5, 0374 TestScenario::ClientCmd, 0375 Protocol::FetchRelationsCommandPtr::create(-1, QList<QByteArray>{}, QLatin1StringView("testresource"))) 0376 << TestScenario::create(5, 0377 TestScenario::ServerCmd, 0378 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0379 item1.mimeType().name().toUtf8(), 0380 item2.id(), 0381 item2.mimeType().name().toUtf8(), 0382 "type", 0383 "foobar1")) 0384 << TestScenario::create(5, 0385 TestScenario::ServerCmd, 0386 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0387 item1.mimeType().name().toUtf8(), 0388 item2.id(), 0389 item2.mimeType().name().toUtf8(), 0390 "type2", 0391 "foobar2")) 0392 << TestScenario::create(5, 0393 TestScenario::ServerCmd, 0394 Protocol::FetchRelationsResponsePtr::create(item3.id(), 0395 item3.mimeType().name().toUtf8(), 0396 item4.id(), 0397 item4.mimeType().name().toUtf8(), 0398 "type", 0399 "foobar3")) 0400 << TestScenario::create(5, 0401 TestScenario::ServerCmd, 0402 Protocol::FetchRelationsResponsePtr::create(item4.id(), 0403 item4.mimeType().name().toUtf8(), 0404 item3.id(), 0405 item3.mimeType().name().toUtf8(), 0406 "type", 0407 "foobar4")) 0408 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0409 0410 QTest::newRow("filter by resource with matching resource") << scenarios; 0411 } 0412 { 0413 Resource res; 0414 res.setName(QStringLiteral("testresource2")); 0415 res.insert(); 0416 0417 TestScenario::List scenarios; 0418 scenarios << FakeAkonadiServer::loginScenario() 0419 << TestScenario::create(5, 0420 TestScenario::ClientCmd, 0421 Protocol::FetchRelationsCommandPtr::create(-1, QList<QByteArray>{}, QLatin1StringView("testresource2"))) 0422 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0423 0424 QTest::newRow("filter by resource with nonmatching resource") << scenarios; 0425 } 0426 { 0427 TestScenario::List scenarios; 0428 scenarios << FakeAkonadiServer::loginScenario() 0429 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(item1.id(), -1, QList<QByteArray>{"type"})) 0430 << TestScenario::create(5, 0431 TestScenario::ServerCmd, 0432 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0433 item1.mimeType().name().toUtf8(), 0434 item2.id(), 0435 item2.mimeType().name().toUtf8(), 0436 "type", 0437 "foobar1")) 0438 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0439 0440 QTest::newRow("filter by left and type") << scenarios; 0441 } 0442 { 0443 TestScenario::List scenarios; 0444 scenarios << FakeAkonadiServer::loginScenario() 0445 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(-1, item2.id(), QList<QByteArray>{"type"})) 0446 << TestScenario::create(5, 0447 TestScenario::ServerCmd, 0448 Protocol::FetchRelationsResponsePtr::create(item1.id(), 0449 item1.mimeType().name().toUtf8(), 0450 item2.id(), 0451 item2.mimeType().name().toUtf8(), 0452 "type", 0453 "foobar1")) 0454 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0455 0456 QTest::newRow("filter by right and type") << scenarios; 0457 } 0458 { 0459 TestScenario::List scenarios; 0460 scenarios << FakeAkonadiServer::loginScenario() 0461 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(item3.id(), QList<QByteArray>{"type"})) 0462 << TestScenario::create(5, 0463 TestScenario::ServerCmd, 0464 Protocol::FetchRelationsResponsePtr::create(item3.id(), 0465 item3.mimeType().name().toUtf8(), 0466 item4.id(), 0467 item4.mimeType().name().toUtf8(), 0468 "type", 0469 "foobar3")) 0470 << TestScenario::create(5, 0471 TestScenario::ServerCmd, 0472 Protocol::FetchRelationsResponsePtr::create(item4.id(), 0473 item4.mimeType().name().toUtf8(), 0474 item3.id(), 0475 item3.mimeType().name().toUtf8(), 0476 "type", 0477 "foobar4")) 0478 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); 0479 0480 QTest::newRow("fetch by side with typefilter") << scenarios; 0481 } 0482 } 0483 0484 void testListRelation() 0485 { 0486 QFETCH(TestScenario::List, scenarios); 0487 0488 mAkonadi.setScenarios(scenarios); 0489 mAkonadi.runTest(); 0490 } 0491 }; 0492 0493 AKTEST_FAKESERVER_MAIN(RelationHandlerTest) 0494 0495 #include "relationhandlertest.moc"