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> &notificationSpy)
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"