File indexing completed on 2024-11-10 04:40:20
0001 /* 0002 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <QObject> 0008 0009 #include "entities.h" 0010 #include "fakeakonadiserver.h" 0011 #include "shared/aktest.h" 0012 0013 #include "private/imapset_p.h" 0014 #include "private/scope_p.h" 0015 0016 #include <QTest> 0017 0018 using namespace Akonadi; 0019 using namespace Akonadi::Server; 0020 0021 class ItemLinkHandlerTest : public QObject 0022 { 0023 Q_OBJECT 0024 0025 FakeAkonadiServer mAkonadi; 0026 0027 public: 0028 ItemLinkHandlerTest() 0029 { 0030 qRegisterMetaType<Akonadi::Protocol::ChangeNotificationList>(); 0031 0032 mAkonadi.init(); 0033 } 0034 0035 Protocol::LinkItemsResponsePtr createError(const QString &error) 0036 { 0037 auto resp = Protocol::LinkItemsResponsePtr::create(); 0038 resp->setError(1, error); 0039 return resp; 0040 } 0041 0042 Protocol::FetchItemsResponse itemResponse(qint64 id, const QString &rid, const QString &rrev, const QString &mimeType) 0043 { 0044 Protocol::FetchItemsResponse item; 0045 item.setId(id); 0046 item.setRemoteId(rid); 0047 item.setRemoteRevision(rrev); 0048 item.setMimeType(mimeType); 0049 return item; 0050 } 0051 0052 private Q_SLOTS: 0053 void testLink_data() 0054 { 0055 QTest::addColumn<TestScenario::List>("scenarios"); 0056 QTest::addColumn<Akonadi::Protocol::ItemChangeNotificationPtr>("notification"); 0057 QTest::addColumn<bool>("expectFail"); 0058 0059 TestScenario::List scenarios; 0060 0061 scenarios << FakeAkonadiServer::loginScenario() 0062 << TestScenario::create(5, 0063 TestScenario::ClientCmd, 0064 Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, ImapInterval(1, 3), 3)) 0065 << TestScenario::create(5, TestScenario::ServerCmd, createError(QStringLiteral("Can't link items to non-virtual collections"))); 0066 QTest::newRow("non-virtual collection") << scenarios << Protocol::ItemChangeNotificationPtr::create() << true; 0067 0068 auto notification = Protocol::ItemChangeNotificationPtr::create(); 0069 notification->setOperation(Protocol::ItemChangeNotification::Link); 0070 notification->setItems({itemResponse(1, QLatin1StringView("A"), QString(), QLatin1StringView("application/octet-stream")), 0071 itemResponse(2, QLatin1StringView("B"), QString(), QLatin1StringView("application/octet-stream")), 0072 itemResponse(3, QLatin1StringView("C"), QString(), QLatin1StringView("application/octet-stream"))}); 0073 notification->setParentCollection(6); 0074 notification->setResource("akonadi_fake_resource_with_virtual_collections_0"); 0075 notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0076 0077 scenarios.clear(); 0078 scenarios << FakeAkonadiServer::loginScenario() 0079 << TestScenario::create(5, 0080 TestScenario::ClientCmd, 0081 Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, ImapInterval(1, 3), 6)) 0082 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); 0083 QTest::newRow("normal") << scenarios << notification << false; 0084 0085 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0086 notification->setItems({itemResponse(4, QLatin1StringView("D"), QString(), QLatin1StringView("application/octet-stream"))}); 0087 scenarios.clear(); 0088 scenarios << FakeAkonadiServer::loginScenario() 0089 << TestScenario::create(5, 0090 TestScenario::ClientCmd, 0091 Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, QList<qint64>{4, 123456}, 6)) 0092 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); 0093 QTest::newRow("existent and non-existent item") << scenarios << notification << false; 0094 0095 scenarios.clear(); 0096 scenarios << FakeAkonadiServer::loginScenario() 0097 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, 4, 6)) 0098 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); 0099 QTest::newRow("non-existent item only") << scenarios << Protocol::ItemChangeNotificationPtr::create() << false; 0100 0101 // FIXME: All RID related operations are currently broken because we reset the collection context before every command, 0102 // and LINK still relies on SELECT to set the collection context. 0103 0104 // scenario.clear(); 0105 // scenario << FakeAkonadiServer::defaultScenario() 0106 // << FakeAkonadiServer::selectCollectionScenario(QLatin1StringView("Collection B")) 0107 // << "C: 3 UID LINK 6 RID (\"F\" \"G\")\n" 0108 // << "S: 3 OK LINK complete"; 0109 // notification.clearEntities(); 0110 // notification.clearEntities(); 0111 // notification.addEntity(6, QLatin1StringView("F"), QString(), QLatin1StringView("application/octet-stream")); 0112 // notification.addEntity(7, QLatin1StringView("G"), QString(), QLatin1StringView("application/octet-stream")); 0113 // QTest::newRow("RID items") << scenario << notification << false; 0114 0115 // scenario.clear(); 0116 // scenario << FakeAkonadiServer::defaultScenario() 0117 // << FakeAkonadiServer::selectResourceScenario(QLatin1StringView("akonadi_fake_resource_with_virtual_collections_0")) 0118 // << "C: 4 HRID LINK ((-1, \"virtual2\") (-1, \"virtual\") (-1, \"\")) UID 5" 0119 // << "S: 4 OK LINK complete"; 0120 // notification.setParentCollection(7); 0121 // notification.clearEntities(); 0122 // notification.addEntity(5, QLatin1StringView("E"), QString(), QLatin1StringView("application/octet-stream")); 0123 // QTest::newRow("HRID collection") << scenario << notification << false; 0124 0125 // scenario.clear(); 0126 // scenario << FakeAkonadiServer::defaultScenario() 0127 // << FakeAkonadiServer::selectResourceScenario(QLatin1StringView("akonadi_fake_resource_with_virtual_collections_0")) 0128 // << FakeAkonadiServer::selectCollectionScenario(QLatin1StringView("Collection B")) 0129 // << "C: 4 HRID LINK ((-1, \"virtual2\") (-1, \"virtual\") (-1, \"\")) RID \"H\"" 0130 // << "S: 4 OK LINK complete"; 0131 // notification.clearEntities(); 0132 // notification.addEntity(8, QLatin1StringView("H"), QString(), QLatin1StringView("application/octet-stream")); 0133 // QTest::newRow("HRID collection, RID items") << scenario << notification << false; 0134 } 0135 0136 void testLink() 0137 { 0138 QFETCH(TestScenario::List, scenarios); 0139 QFETCH(Protocol::ItemChangeNotificationPtr, notification); 0140 QFETCH(bool, expectFail); 0141 0142 mAkonadi.setScenarios(scenarios); 0143 mAkonadi.runTest(); 0144 0145 auto notificationSpy = mAkonadi.notificationSpy(); 0146 if (notification->operation() != Protocol::ItemChangeNotification::InvalidOp) { 0147 QTRY_COMPARE(notificationSpy->count(), 1); 0148 const Protocol::ChangeNotificationList notifications = notificationSpy->takeFirst().first().value<Protocol::ChangeNotificationList>(); 0149 QCOMPARE(notifications.count(), 1); 0150 QCOMPARE(*notifications.first().staticCast<Protocol::ItemChangeNotification>(), *notification); 0151 } else { 0152 QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value<Protocol::ChangeNotificationList>().isEmpty()); 0153 } 0154 0155 const auto entities = notification->items(); 0156 for (const auto &entity : entities) { 0157 if (expectFail) { 0158 QVERIFY(!Collection::relatesToPimItem(notification->parentCollection(), entity.id())); 0159 } else { 0160 QVERIFY(Collection::relatesToPimItem(notification->parentCollection(), entity.id())); 0161 } 0162 } 0163 } 0164 0165 void testUnlink_data() 0166 { 0167 QTest::addColumn<TestScenario::List>("scenarios"); 0168 QTest::addColumn<Akonadi::Protocol::ItemChangeNotificationPtr>("notification"); 0169 QTest::addColumn<bool>("expectFail"); 0170 0171 TestScenario::List scenarios; 0172 0173 scenarios << FakeAkonadiServer::loginScenario() 0174 << TestScenario::create(5, 0175 TestScenario::ClientCmd, 0176 Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, ImapInterval(1, 3), 3)) 0177 << TestScenario::create(5, TestScenario::ServerCmd, createError(QStringLiteral("Can't link items to non-virtual collections"))); 0178 QTest::newRow("non-virtual collection") << scenarios << Protocol::ItemChangeNotificationPtr::create() << true; 0179 0180 auto notification = Protocol::ItemChangeNotificationPtr::create(); 0181 notification->setOperation(Protocol::ItemChangeNotification::Unlink); 0182 notification->setItems({itemResponse(1, QLatin1StringView("A"), QString(), QLatin1StringView("application/octet-stream")), 0183 itemResponse(2, QLatin1StringView("B"), QString(), QLatin1StringView("application/octet-stream")), 0184 itemResponse(3, QLatin1StringView("C"), QString(), QLatin1StringView("application/octet-stream"))}); 0185 notification->setParentCollection(6); 0186 notification->setResource("akonadi_fake_resource_with_virtual_collections_0"); 0187 notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); 0188 scenarios.clear(); 0189 scenarios << FakeAkonadiServer::loginScenario() 0190 << TestScenario::create(5, 0191 TestScenario::ClientCmd, 0192 Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, ImapInterval(1, 3), 6)) 0193 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); 0194 QTest::newRow("normal") << scenarios << notification << false; 0195 0196 notification = Protocol::ItemChangeNotificationPtr::create(*notification); 0197 notification->setItems({itemResponse(4, QLatin1StringView("D"), QString(), QLatin1StringView("application/octet-stream"))}); 0198 scenarios.clear(); 0199 scenarios << FakeAkonadiServer::loginScenario() 0200 << TestScenario::create(5, 0201 TestScenario::ClientCmd, 0202 Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, QList<qint64>{4, 2048}, 6)) 0203 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); 0204 QTest::newRow("existent and non-existent item") << scenarios << notification << false; 0205 0206 scenarios.clear(); 0207 scenarios << FakeAkonadiServer::loginScenario() 0208 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, 4096, 6)) 0209 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); 0210 QTest::newRow("non-existent item only") << scenarios << Protocol::ItemChangeNotificationPtr::create() << false; 0211 0212 // FIXME: All RID related operations are currently broken because we reset the collection context before every command, 0213 // and LINK still relies on SELECT to set the collection context. 0214 0215 // scenario.clear(); 0216 // scenario << FakeAkonadiServer::defaultScenario() 0217 // << FakeAkonadiServer::selectCollectionScenario(QLatin1StringView("Collection B")) 0218 // << "C: 4 UID UNLINK 6 RID (\"F\" \"G\")" 0219 // << "S: 4 OK LINK complete"; 0220 // notification.clearEntities(); 0221 // notification.clearEntities(); 0222 // notification.addEntity(6, QLatin1StringView("F"), QString(), QLatin1StringView("application/octet-stream")); 0223 // notification.addEntity(7, QLatin1StringView("G"), QString(), QLatin1StringView("application/octet-stream")); 0224 // QTest::newRow("RID items") << scenario << notification << false; 0225 0226 // scenario.clear(); 0227 // scenario << FakeAkonadiServer::defaultScenario() 0228 // << FakeAkonadiServer::selectResourceScenario(QLatin1StringView("akonadi_fake_resource_with_virtual_collections_0")) 0229 // << "C: 4 HRID UNLINK ((-1, \"virtual2\") (-1, \"virtual\") (-1, \"\")) UID 5" 0230 // << "S: 4 OK LINK complete"; 0231 // notification.setParentCollection(7); 0232 // notification.clearEntities(); 0233 // notification.addEntity(5, QLatin1StringView("E"), QString(), QLatin1StringView("application/octet-stream")); 0234 // QTest::newRow("HRID collection") << scenario << notification << false; 0235 0236 // scenario.clear(); 0237 // scenario << FakeAkonadiServer::defaultScenario() 0238 // << FakeAkonadiServer::selectCollectionScenario(QLatin1StringView("Collection B")) 0239 // << FakeAkonadiServer::selectResourceScenario(QLatin1StringView("akonadi_fake_resource_with_virtual_collections_0")) 0240 // << "C: 4 HRID UNLINK ((-1, \"virtual2\") (-1, \"virtual\") (-1, \"\")) RID \"H\"" 0241 // << "S: 4 OK LINK complete"; 0242 // notification.clearEntities(); 0243 // notification.addEntity(8, QLatin1StringView("H"), QString(), QLatin1StringView("application/octet-stream")); 0244 // QTest::newRow("HRID collection, RID items") << scenario << notification << false; 0245 } 0246 0247 void testUnlink() 0248 { 0249 QFETCH(TestScenario::List, scenarios); 0250 QFETCH(Protocol::ItemChangeNotificationPtr, notification); 0251 QFETCH(bool, expectFail); 0252 0253 mAkonadi.setScenarios(scenarios); 0254 mAkonadi.runTest(); 0255 0256 auto notificationSpy = mAkonadi.notificationSpy(); 0257 if (notification->operation() != Protocol::ItemChangeNotification::InvalidOp) { 0258 QTRY_COMPARE(notificationSpy->count(), 1); 0259 const auto notifications = notificationSpy->takeFirst().first().value<Protocol::ChangeNotificationList>(); 0260 QCOMPARE(notifications.count(), 1); 0261 QCOMPARE(*notifications.first().staticCast<Protocol::ItemChangeNotification>(), *notification); 0262 } else { 0263 QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value<Protocol::ChangeNotificationList>().isEmpty()); 0264 } 0265 0266 const auto entities = notification->items(); 0267 for (const auto &entity : entities) { 0268 if (expectFail) { 0269 QVERIFY(Collection::relatesToPimItem(notification->parentCollection(), entity.id())); 0270 } else { 0271 QVERIFY(!Collection::relatesToPimItem(notification->parentCollection(), entity.id())); 0272 } 0273 } 0274 } 0275 }; 0276 0277 AKTEST_FAKESERVER_MAIN(ItemLinkHandlerTest) 0278 0279 #include "itemlinkhandlertest.moc"